Reproduced Exploit
Mystic Finance syncRewards: lastRewardAmount stores the cycle delta
Chain
Other
Category
logic
Date
Feb 2025
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: 57712-c-01-miscalculation-in-rewardswill-give-toomuchrewardstouser. Standalone Foundry PoC and full write-up: 57712-c-01-miscalculation-in-rewardswill-give-toomuchrewardstouser_exp in the
evm-hack-registrymirror.
Vulnerability classes: vuln/logic/reward-calculation
Reproduction: faithful local reproduction of AuditVault 57712, using the report's own 10 ether cycle numbers.
nextRewards = yieldEth - lastRewardAmount, thenlastRewardAmountis set tonextRewardsinstead of cumulative yield.
Root cause#
lastRewardAmount is supposed to track cumulative yield. The function stores only the latest delta. The next cycle subtracts that stale delta from a larger yieldEth and books too much.
uint256 nextRewards = yieldEth - lastRewardAmount;
accountedRewards += nextRewards;
// @> VULN: lastRewardAmount stores the cycle delta, not cumulative yieldEth
lastRewardAmount = nextRewards;
accPerShare += nextRewards * 1e18 / totalShares;
Cycle 1: yield 10, next 10, last becomes 10. Cycle 2: yield 20, next 10, last is stored as 10 instead of 20. Cycle 3: yield 30, next is 20. Accounted rewards are 40 against 30 of real yield.
Attack path#
Impact#
Fair shares of the 30 ether deposited are 15 and 15. The first withdrawer receives 20 ether. The other staker can withdraw only the remaining 10 ether, a 5 ether loss. That 5 ether is forwarded to the sink. The fixed syncRewards sets lastRewardAmount = yieldEth, accounts 30 ether, and pays each staker 15 ether.
PoC#
cd 57712-c-01-miscalculation-in-rewardswill-give-toomuchrewardstouser_exp
forge test -vv
Sources#
- AuditVault finding 57712
- Kann, Mystic Finance: https://github.com/Kann-Audits/Kann-Audits/blob/main/reports/md-format/private-audits-reports/Mystic%20Finance.md
Sources & further analysis#
Reproductions & code
- Standalone PoC + full trace: 57712-c-01-miscalculation-in-rewardswill-give-toomuchrewardstouser_exp (evm-hack-registry mirror).
- AuditVault finding: 57712-c-01-miscalculation-in-rewardswill-give-toomuchrewardstouser.
Alerts & third-party analyses
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.