Reproduced Exploit
Elytra: static strategy-allocation tracker mis-reports vault TVL
Chain
Other
Category
untagged
Date
Jan 1970
Source
AuditVault
EVM Playground
Source-level debugger — step opcodes and Solidity in sync
The attack is replayed in an in-browser EVM preloaded with the exact dumped fork state. The execution tree shows every call; step by Solidity line or by opcode across all depths — source, Stack, Memory, Storage, Balances (native / ERC-20 / NFT), Transient storage and Return value stay in sync. Click a tree node, opcode, or source line to jump. No backend, no live RPC.
Source & credit. Reproduction of a public audit finding curated by AuditVault — the original finding: Elytra-security-review_2025-07-10. The historical source/toolchain is unavailable; this entry is documentation only and claims no executable Forge PoC.
Vulnerability classes: vuln/accounting · vuln/logic · vuln/frontrun
Reproduction: a faithful minimal reproduction of the vulnerable finding — the audited
getTotalAssetTVLview and the allocation/deallocation tracker updates are reproduced verbatim (marked@>) with faithful minimal doubles; local deploy, no fork.
Root cause#
Elytra tracks how many assets sit inside its restaking strategies with a static storage counter, assetsAllocatedToStrategies[asset], and sums that counter into getTotalAssetTVL(). The counter is only bumped on allocate (+= amount) and decremented on deallocate by the tokens actually withdrawn (-= withdrawn) — it is never reconciled against the strategy's real balance, so yield that grows inside the strategy is invisible to it. The vulnerable accounting, reproduced verbatim from the finding:
function getTotalAssetTVL(address asset) public view returns (uint256 totalTVL) {
uint256 poolBalance = IERC20(asset).balanceOf(address(this));
uint256 strategyAllocated = assetsAllocatedToStrategies[asset];
uint256 unstakingVaultBalance = _getUnstakingVaultBalance(asset);
return poolBalance + strategyAllocated + unstakingVaultBalance;
}
// Called during allocation
assetsAllocatedToStrategies[asset] += amount;
// Called during deallocation
uint256 withdrawn = IElytraStrategy(strategy).withdraw(asset, amount);
if (withdrawn <= assetsAllocatedToStrategies[asset]) {
@> assetsAllocatedToStrategies[asset] -= withdrawn;
} else {
assetsAllocatedToStrategies[asset] = 0;
}
strategyAllocated is a manually-maintained mirror, not a live balance. Once the strategy's real holdings and the counter diverge (yield, realized P&L, or slashing), getTotalAssetTVL() reports a number that no longer matches the assets the protocol actually controls — and elyAsset is priced off that number.
Why it's exploitable here#
Following the finding's worked example with a 6-decimal asset (USDC):
- Depositors fund the vault with
100. The operator allocates all100to a strategy → counter= 100, strategy holds100, pool= 0. - The strategy accrues
+20of yield → strategy now holds120, but the counter is still100. - The operator deallocates
60.withdrawreturns60, so the branch runscounter -= 60 => 40; the strategy still holds120 - 60 = 60and the pool holds60. getTotalAssetTVL()= pool60+ counter40+ unstaking0=100, but the protocol's real holdings are pool60+ strategy60=120.
The reported TVL trails real holdings by the full 20 of un-credited yield, so elyAsset is deflated. A user who observes the un-accounted yield can mint elyAsset at the deflated price, wait for the operator to deallocate (realizing the yield into TVL and spiking the price), then redeem for a risk-free profit that belongs to existing holders. The same static-mirror flaw runs the other way for realized losses and slashing — the counter cannot be reduced without a withdrawal, so TVL and elyAsset stay over-inflated, allowing withdrawals of more than the protocol truly owns.
Attack path#
Marked-line walkthrough (Playground)#
The EVM Playground pins each step to the exact executed source line in 0xce01759b…:
- L125 — TVL sums the three balances: getTotalAssetTVL adds the pool balance, the static strategy tracker, and the unstaking balance into the number that prices elyAsset.
- L132 — Vault funds the strategy: Setup: during allocation the vault transfers the principal into the restaking strategy, which now holds the real tokens.
- L135 — Static tracker records allocation: Setup: assetsAllocatedToStrategies is bumped by the allocated amount, recording 100 as the strategy's tracked holdings.
- L140 — Operator deallocates part of it: The operator withdraws part of the position from the strategy, pulling 60 tokens back into the vault's pool balance.
- L144 — Tracker drops accrued yield: Root cause: the tracker is decremented only by tokens withdrawn and never reconciled to the strategy's real balance, so in-strategy yield is silently lost.
- L150 — Unstaking balance is read: The unstaking-vault component of TVL is queried; with no pending unstakes it contributes nothing to the reported total.
- L152 — Unstaking resolves to zero: It returns zero, so reported TVL now rests entirely on the pool balance plus the stale, understated strategy tracker.
- L158 — Un-credited yield marks the gap: Reported TVL (100) trails real holdings (120) by the full 20 of un-credited yield, mispricing elyAsset; the gap is marked at the sink.
PoC#
Registry (Foundry, local deploy — verbatim vulnerable source + harm-asserting test):
cd 63547-h-04-strategy-allocation-tracking-errors-affect-tvl-calculat_exp && forge test -vvv
The browser Playground replays the same synthetic opcode-for-opcode and measures the harm: allocate 100, accrue +20 yield, deallocate 60, and read getTotalAssetTVL = 100 against real holdings of 120 — a 20 TVL gap that mis-prices elyAsset. Both gates are green (registry forge test PASS + Playground _verify-poc VERDICT: PASS).
Sources & further analysis#
Reproductions & code
- No executable Forge reproduction is claimed; the historical source/toolchain was unavailable for this finding.
- AuditVault finding: Elytra-security-review_2025-07-10.
- Upstream DeFiHackLabs PoC directory: src/test.
Alerts & third-party analyses
- DeFiHackLabs incident explorer: search "Elytra: static strategy-allocation tracker mis-reports vault TVL".
- Web3Sec X hacked database: search.
- Rekt leaderboard: search.
- Solodit incident search: search.
These dashboards index community alerts tweets, post-mortems, and independent write-ups. Reach them through the protocol name above to cross-check this reproduction against other analyses.