58739 sc insight decimals mismatch causes 1e12 under reporting in strategy returns letting allocations silently exceed per strategy and global caps

Submitted on Nov 4th 2025 at 10:52:22 UTC by @manvi for Audit Comp | Alchemix V3arrow-up-right

  • Report ID: #58739

  • Report Type: Smart Contract

  • Report severity: Insight

  • Target: https://github.com/alchemix-finance/v3-poc/blob/immunefi_audit/src/MYTStrategy.sol

  • Impacts:

    • Smart contract unable to operate due to lack of token funds

    • Protocol insolvency

Description

Brief/Intro

I analyzed how the allocator enforces per-strategy caps and observed that it trusts strategy-reported deltas / TVL (e.g., return value change from allocate/deallocate and/or realAssets()) without enforcing a canonical precision.

If a strategy internally treats an 18-dec vault asset as a 6-dec unit (or otherwise returns values in a mismatched base), the allocator under-counts the moved TVL—by as much as 1e12—so per-strategy caps never trigger while real funds flow into the adapter.

This silently defeats risk limits and enables excess TVL concentration, which can lead to material losses if the adapter later fails - rising to protocol insolvency.

Vulnerability Details

I have observed that the Allocator code assumes strategy-reported amounts are in the allocator’s expected unit/precision. There is no normalization to a canonical 18-dec WAD before doing cap math.

There is no enforcement that change returned by a strategy equals the requested assets (modulo small rounding). A strategy can legally return much smaller change, and the allocator will accept it as TVL delta.

Surface exposed by interface:

IMYTStrategy.allocate(bytes data, uint256 assets, bytes4 selector, address sender) returns (bytes32[] strategyIds, int256 change)

IMYTStrategy.deallocate(...) returns (..., int256 change)

IMYTStrategy.realAssets() external view returns (uint256)

The allocator relies on these values for cap / TVL accounting but does not normalize or sanity-check them.

Root Cause Code:

src/MYTStrategy.sol

The allocator's cap enforcement (in src/AlchemistAllocator.sol) uses these strategy-reported numbers for TVL/cap checks. (There's no canonical 18-dec normalization or invariant that change = assets.)

Exploit scenario

A strategy (malicious or simply buggy) scales its reported allocation delta by 1/1e12 (e.g., treats 18-dec assets as 6-dec units).

The allocator calls allocate(assets). The strategy actually moves assets funds but returns change = assets / 1e12.

The allocator adds change to the strategy's recorded TVL and compares to cap - which now looks far below the limit - allowing more and more assets to flow.

The real TVL of the strategy grows well beyond cap, but recorded TVL doesn't.

If that adapter later experiences loss, the excess TVL (that should have been blocked by caps) is at risk -> protocol-scale losses or system unavailability.

Impact Details

Risk limits defeated: Per-strategy cap / globalCap do not bind actual funds.

Systemic loss amplification: If the over-concentrated adapter underperforms or is compromised, the excess TVL (that should have been blocked) is exposed -> Protocol insolvency plausible.

Operational failure: Out-of-sync accounting causes unexpected reverts, liquidity shortages, or mispriced risk -> Smart contract unable to operate due to lack of token funds.

References

MYTStrategy.sol (core bug location) IMYTStrategy.sol (params, cap, interface used by allocator) AlchemistAllocator.sol (consumes strategy caps/realAssets) ZeroXSwapVerifier.sol (context for allocation/deallocation flows)

Proof of Concept

I have demonstrated this issue with a runnable POC

PoC file: src/test/poc/Allocator_CapDecimals_Bypass.t.sol

My test creates a minimal strategy that under-reports by 1e12 and demonstrates both allocate and deallocate paths under-counting.

What the PoC does

Implements a minimal strategy that under-reports allocation/deallocation deltas by /1e12 (simulating a 6-dec vs 18-dec unit mismatch).

Calls allocate(assets) and deallocate(assets) through the normal MYTStrategy surface so the flow mirrors production.

Records the returned change that the allocator would trust for TVL/cap math.

Content of my POC file

Run my POC file from Repo Root :

My Console Output :

What my PoC proved

For a real move of assets = 1e18, the strategy reports change = 1e6 - an under-count of 1e12.

Both allocation and deallocation paths under-count, meaning per-strategy caps will not trigger while real funds flow, enabling TVL to exceed configured caps.

This defeats allocator risk limits and can concentrate outsized exposure in one adapter, creating a plausible path to protocol insolvency or operational failure if that adapter loses funds.

Was this helpful?