Reproduced Exploit
infiniFi: unwinding in the same epoch takes 50 from Bob
balanceOf starts at fromEpoch - 1. A user who already earned the locking reward for epoch 5 can startUnwinding in that epoch and still be counted. The 100 pot is split with Bob.
Chain
Other
Category
logic
Date
Mar 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: 55050-double-claiming-of-accrued-rewards-via-unwinding-after-accru. Standalone Foundry PoC and full write-up: 55050-double-claiming-of-accrued-rewards-via-unwinding-after-accru_exp in the
evm-hack-registrymirror.
Vulnerability classes: vuln/logic/reward-calculation
Key info#
| Protocol | infiniFi |
| Finding | Spearbit, AuditVault 55050 |
| Vulnerable code | Unwinding.balanceOf |
| Harm | After taking 100 on the locking side, the user is also paid 50 of the 100 unwinding pot. Bob receives 50 instead of 100. The fixed balanceOf pays Bob 100. |
| Chain | local synthetic |
TL;DR#
balanceOf starts at fromEpoch - 1. A user who already earned the locking reward for epoch 5 can startUnwinding in that epoch and still be counted. The 100 pot is split with Bob.
The vulnerable code#
// @> VULN: fromEpoch - 1 includes the arrival epoch
if (epoch < p.fromEpoch - 1) return 0;
Root cause#
The arrival epoch is included because the loop begins one epoch before fromEpoch. The user was already paid for that epoch on the locking side.
Preconditions#
Bob has been unwinding since epoch 1 with 100 shares. The user was allocated 100 of locking rewards for epoch 5.
Attack walkthrough#
- Record the 100 locking allocation. See output.txt.
- Seed Bob at epoch 1 and start unwinding in epoch 5.
balanceOffor epoch 5 returns 100 shares.- The 100 pot is split 50 and 50.
- The arriving user receives 50.
- Bob receives 50. The fixed module excludes the arrival epoch and pays Bob 100.
Diagrams#
Impact#
Bob loses 50 of the epoch's unwinding rewards. Skipping the arrival epoch pays him the full 100.
Remediation#
Do not count a position for epochs at or before the epoch in which it started unwinding.
How to reproduce#
cd 55050-double-claiming-of-accrued-rewards-via-unwinding-after-accru_exp
forge test -vv
Sources & further analysis#
Reproductions & code
- Standalone PoC + full trace: 55050-double-claiming-of-accrued-rewards-via-unwinding-after-accru_exp (evm-hack-registry mirror).
- AuditVault finding: 55050-double-claiming-of-accrued-rewards-via-unwinding-after-accru.
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.