Reproduced Exploit
Blueberry HyperEVM Vault: donated tokens inflate share price but can never be redeemed
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: Blueberry-security-review_2025-03-26. The historical source/toolchain is unavailable; this entry is documentation only and claims no executable Forge PoC.
Vulnerability classes: vuln/logic · vuln/dos
Reproduction: a faithful minimal reproduction of the vulnerable finding — the vulnerable total-assets accounting (
_totalEscrowValue) and the escrow equity check (VaultEscrow.tvl/withdraw) are reproduced verbatim (marked@>) with faithful minimal doubles; local deploy, no fork.
Root cause#
HyperEvmVault._totalEscrowValue computes the vault's total assets (the share-price numerator) by summing each escrow's tvl(). VaultEscrow.tvl() returns vaultEquity_ + assetBalance, i.e. the L1-vault equity plus the escrow's raw ERC20 balance — so tokens donated directly to an escrow inflate total assets even though they are never pushed into the L1 vault and never become equity. The vulnerable lines, reproduced verbatim:
function _totalEscrowValue(V1Storage storage $) internal view returns (uint256 assets_) {
uint256 escrowLength = $.escrows.length;
for (uint256 i = 0; i < escrowLength; ++i) {
VaultEscrow escrow = VaultEscrow($.escrows[i]);
@> assets_ += escrow.tvl();
}
if ($.lastL1Block == l1Block()) {
assets_ += $.currentBlockDeposits;
}
return assets_ - $.requestSum.assets;
}
On redemption, VaultEscrow.withdraw enforces require(vaultEquity_ >= lastWithdraws), and vaultEquity_ only reflects assets actually held in the L1 vault — it never sees the donation. The donation-backed portion of every share is therefore phantom TVL: it raises the price shares are sold at but can never be paid out.
Why it's exploitable here#
Following the finding's worked example:
- The attacker deposits
100, minting100shares; L1 equity is100. - The attacker donates
100directly to the escrow.tvl()now returnsequity(100) + balance(100) = 200, sototalAssets = 200for100shares — the share price has doubled. - An honest user deposits
200real assets. At the inflated price they mint only200 * 100 / 200 = 100shares (total supply200, total assets400). - The attacker redeems
100shares (worth200), which succeeds and drains the L1 equity down to100. - The honest user redeems
100shares (worth200), but the escrow's equity check sees only100of L1 equity against200owed and always reverts. The100donated tokens are stuck in the escrow forever, and the honest user's200assets are un-redeemable.
Attack path#
Marked-line walkthrough (Playground)#
The EVM Playground pins each step to the exact executed source line in 0xbd4fd5a3…:
- L279 — Vault totals every escrow's assets: The vault enters
_totalEscrowValue, the function that sums each escrow's assets to produce the numerator every share price is based on. - L280 — Total assets counts donated tokens: Root cause: the loop sums each escrow's
tvl(), which includes raw tokens donated straight to the escrow and never deposited into the L1 vault. - L293 — totalAssets exposes inflated total:
totalAssets()returns that donation-inflated sum, so the vault now reports more assets than it can ever actually pay out on redemption. - L304 — Shares priced against inflated total:
convertToAssetsmultiplies shares by the inflatedtotalAssets, promising every redeemer more assets than the L1 vault actually holds. - L313 — Honest deposit priced at inflation: In
deposit, the honest user's shares are computed against the doubled price, so their real 200 assets mint only 100 shares. - L325 — Honest user redeems 100 shares: The honest user calls
redeem, converting their 100 shares back to 200 assets against the still-inflated total supply. - L334 — Equity check reverts redemption:
escrow.withdrawrequires L1 equity to cover the amount owed, but equity never counted the 100 donated tokens, so redemption reverts and funds stay locked.
PoC#
Registry (Foundry, local deploy — verbatim vulnerable source + harm-asserting test):
cd 61470-h-02-donated-tokens-are-never-deposited-into-vaults-pashov-a_exp && forge test -vvv
The browser Playground replays the same synthetic opcode-for-opcode and measures the harm: a 100-token donation doubles the share price, and the honest user's 200-asset redemption reverts on the escrow equity check while the donated tokens stay locked. 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: Blueberry-security-review_2025-03-26.
- Upstream DeFiHackLabs PoC directory: src/test.
Alerts & third-party analyses
- DeFiHackLabs incident explorer: search "Blueberry HyperEVM Vault: donated tokens inflate share price but can never be redeemed".
- 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.