Reproduced Exploit
RipIt: acceptOffer books the offerCurrency fee into the single acceptedCurrency-denominated total
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: 62542-h-05-currency-validation-missing-in-listing-and-offer-reques. Standalone Foundry PoC and full write-up: 62542-h-05-currency-validation-missing-in-listing-and-offer-reques_exp in the
evm-hack-registrymirror.
Vulnerability classes: vuln/locked-funds · vuln/unfair-mint · vuln/reward-accounting
Reproduction: a faithful minimal reproduction of the vulnerable finding — the vulnerable function is reproduced verbatim (marked
@>) with faithful minimal doubles; local deploy, no fork.
Root cause#
acceptOffer books the offerCurrency fee into the single acceptedCurrency-denominated totalPendingFees scalar; an attacker offer in a worthless token inflates totalPendingFees to 2F while only F of real USDC is held, so emergencyShutdown (the only fee-withdrawal path) permanently reverts and the real F of USDC fees is locked.
uint256 sellerAmount = price - feeAmount;
// Update state before external calls
totalPendingFees += feeAmount; // @> fee booked into the single acceptedCurrency-denominated scalar while it is actually collected in offerCurrency below (no offerCurrency==acceptedCurrency check) -> phantom, unbacked fees
// External calls after state changes
IERC20(offers[i].request.offerCurrency).transferFrom(offers[i].request.requester, offers[i].receiver, sellerAmount);
Why it's exploitable here#
acceptOffer books the offerCurrency fee into the single acceptedCurrency-denominated totalPendingFees scalar; an attacker offer in a worthless token inflates totalPendingFees to 2F while only F of real USDC is held, so emergencyShutdown (the only fee-withdrawal path) permanently reverts and the real F of USDC fees is locked.
Attack path#
Marked-line walkthrough (Playground)#
The EVM Playground pins each step to the exact executed source line in 0xce01759b82…:
- L158 — Build listing signature hash: Setup: pure helper that hashes a listing request for signature checks — unrelated to the fee-accounting bug.
- L162 — Hash includes tokenId: Setup:
tokenIdis one of the fields folded into the listing signature hash. - L228 — Add offer fee to one scalar: Root-cause: the offer's fee (in arbitrary
offerCurrency) is added to the single acceptedCurrency-denominatedtotalPendingFees, with no currency validation. - L230 — Pay seller in offer currency: Transfers the sale amount to the seller in the buyer-chosen
offerCurrency, which can be a worthless token. - L231 — Pull fee in offer currency: Pulls the fee into the contract in
offerCurrency, so a worthless-token fee counts towardtotalPendingFeesbut holds no real value. - L236 — Only fee-withdrawal path: The sole path that pays out accrued fees; it must move
totalPendingFeesworth of the real acceptedCurrency. - L245 — Reset accepted currency: Would clear
acceptedCurrencyon shutdown, but the inflatedtotalPendingFeesmakes the preceding real-USDC transfer revert, locking the fees.
PoC#
Registry (Foundry, local deploy — verbatim vulnerable source + harm-asserting test + negative control):
cd 62542-h-05-currency-validation-missing-in-listing-and-offer-reques_exp
forge test -vvv
The browser Playground replays the same synthetic opcode-for-opcode and measures the harm: acceptOffer books the offerCurrency fee into the single acceptedCurrency-denominated totalPendingFees scalar; an attacker offer in a worthle. Both gates are green (registry forge test PASS + Playground _verify-poc VERDICT: PASS).
Sources & further analysis#
Reproductions & code
- Standalone PoC + full trace: 62542-h-05-currency-validation-missing-in-listing-and-offer-reques_exp (evm-hack-registry mirror).
- AuditVault finding: 62542-h-05-currency-validation-missing-in-listing-and-offer-reques.
- Upstream DeFiHackLabs PoC directory: src/test.
Alerts & third-party analyses
- DeFiHackLabs incident explorer: search "RipIt: acceptOffer books the offerCurrency fee into the single acceptedCurrency-denominated total".
- 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.