Calculated from recorded token losses using historical USD prices at the incident time.
0xa0ff1de61793b0915038e644a2b45372be8d49e1060b6b2cd5e3482d7d4325ba0x46280c1a2e17cfc151f50a885363408368bb163aBSCRevamp on BSC was exploited in transaction 0xa0ff1de61793b0915038e644a2b45372be8d49e1060b6b2cd5e3482d7d4325ba after the protocol had already reached an insolvent public state. The adversary flash-borrowed WBNB, listed a worthless attacker-created token through the public listNewAsset entrypoint, then used two attacker-controlled identities to call revamp() twice and withdraw() twice inside one transaction. The measurable outcome was a sender-side native gain of 2989222516365223040 wei while Revamp's native balance fell from 3207830444822227643 wei to 1 wei.
The root cause is an accounting error in Revamp's reward logic. Each new netValue is treated both as immediately distributable reward for earlier participants and as fully withdrawable principal for the new depositor. That double counting lets an attacker manufacture claimable rewards from temporary capital and withdraw more native value than the protocol can safely support.
Revamp tracks public principal with totalNativeContributed() and calculates user rewards through pendingReward(address). The exploit only needs that global contributed amount to be nonzero before the adversary starts, because the second attacker-controlled deposit must have prior principal to reward.
Three protocol details matter:
revamp(address,uint256,address) accepts listed tokens but, per the analyzed victim logic and reproduced exploit, does not enforce that the ERC20 side has real economic value relative to .msg.valuependingReward(address) caps payout at 2x contributed principal, which constrains extraction size but does not prevent the attack.Before the exploit transaction, the forkable public pre-state already showed insolvency: totalNativeContributed() was 27806188443800000000 wei while the contract held only 3207830444822227643 wei. That gap is the condition that made immediate extraction possible.
This is an ATTACK-class solvency failure in Revamp's native accounting. The victim components are Revamp.revamp(address,uint256,address), Revamp.withdraw(uint256), and Revamp.pendingReward(address) at 0x46280C1A2e17CfC151f50a885363408368BB163A. The safety invariant is straightforward: a user's net deposit cannot remain fully withdrawable principal while the same value is also fully booked as distributable reward to earlier users.
The reported breakpoint is the correct one. In the vulnerable flow, revamp() uses the new deposit's netValue to increase the reward accumulator for existing participants before the same netValue is added into both the depositor's contributed principal and global totalNativeContributed. No reserve is created to offset that reward credit. withdraw() then pays reward-derived native value without reducing totalNativeContributed, so liabilities remain overstated after cash-out. The result is a protocol that can be drained while still reporting the same public principal number it had before the attacker entered and exited the cycle.
The exploit begins from the public pre-state immediately before block 87423341, where Revamp already reported 27.8061884438 BNB of contributed principal but held only 3.207830444822227643 BNB natively. That mismatch is visible in the reproduced fork and is part of the validator pre-check.
The on-chain trace shows the attacker-created contract at 0x8b959ecDd652Dee3272F1C9684dBF42Ae671eB40 interacting directly with Revamp and a freshly created helper at 0x97E2AB43e63839F48E57e536986bA21280E8Bd54. The first meaningful victim interaction is a public asset listing call with 0.02 BNB of value, followed by a first Revamp::revamp{value: 1693680277097269082} call using 1e18 fake tokens and the helper as referral. The trace then shows a second Revamp::revamp{value: 62112151354194538164} call from the helper using the same worthless token.
Representative seed-trace excerpts:
Revamp::revamp{value: 1693680277097269082}(..., 1000000000000000000, 0x97E2AB43...)
Revamp::revamp{value: 62112151354194538164}(..., 1000000000000000000, 0x8b959ecD...)
Revamp::pendingReward(0x8b959ecDd652Dee3272F1C9684dBF42Ae671eB40)
Revamp::withdraw(4811745667233341463)
Revamp::withdraw(58820207332422227642)
That sequence matches the accounting failure described in root_cause.json. The first attacker identity seeds principal. The second attacker identity injects a much larger temporary deposit, which increases the reward state seen by the first identity. The first identity then withdraws principal plus inflated reward, and the second identity withdraws its principal. Because reward payout is sourced from the same native coins that remain booked as principal, the withdrawals consume real balance without curing the liability overstatement.
The balance diff confirms the economic effect. The transaction sender 0x42579d63bd5945fcfde5adff4edc40c34869914e increased from 221214000000000001 wei to 3210436516365223041 wei, a net gain of 2989222516365223040 wei. Over the same transaction, Revamp fell from 3207830444822227643 wei to 1 wei, a loss of 3207830444822227642 wei. Those numbers are consistent with the claim that the exploit drains native value while leaving protocol accounting inconsistent.
The exploit is ACT because every required action is public and permissionless: borrow liquidity, deploy fresh contracts, list a new token through the public interface, make two deposits from attacker-controlled identities, and withdraw against public accounting state. No privileged key, admin role, or private attacker artifact is required.
The adversary cluster is evidence-backed:
0x42579d63bd5945fcfde5adff4edc40c34869914e: EOA sender and final profit recipient.0x8b959ecDd652Dee3272F1C9684dBF42Ae671eB40: primary attack contract that receives flash liquidity, lists the fake asset, makes the first deposit, withdraws reward plus principal, repays the loan, and forwards profit.0x97E2AB43e63839F48E57e536986bA21280E8Bd54: helper contract that makes the second deposit and withdraws its principal.The execution flow is:
pendingReward rises to the exploitable cap.The trace records both key withdrawals:
emit WithdrawDone(user: 0x8b959ecDd652Dee3272F1C9684dBF42Ae671eB40, withdrawnAmount: 4811745667233341463)
emit WithdrawDone(user: 0x97E2AB43e63839F48E57e536986bA21280E8Bd54, withdrawnAmount: 58820207332422227642)
This is the exact on-chain realization of the reported strategy: small seed principal, reward inflation via second deposit, cash-out, loan repayment, profit.
The directly observed seed-transaction loss is native BNB:
BNB320783044482222764218Revamp's native balance was effectively exhausted to 1 wei during the transaction, while the reported totalNativeContributed returned to its prior public value. That means existing participants were left facing the same reported liability with almost no backing native balance. The exploit is repeatable by any unprivileged actor whenever sufficient remaining balance and public state conditions exist to complete the cycle.
0xa0ff1de61793b0915038e644a2b45372be8d49e1060b6b2cd5e3482d7d4325ba0x46280C1A2e17CfC151f50a885363408368BB163A0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095cpendingReward, and withdrawalshttps://bscscan.com/address/0x46280c1a2e17cfc151f50a885363408368bb163a#code