Calculated from recorded token losses using historical USD prices at the incident time.
0x9fe19093a62a7037d04617b3ac4fbf5cb2d75d8cb6057e7e1b3c75cbbd5a5adc0xd3d4b46db01c006fb165879f343fc13174a1ceebBSC0xa269556edc45581f355742e46d2d722c5f3f551aBSCOn BNB Smart Chain block 26685504, transaction 0x9fe19093a62a7037d04617b3ac4fbf5cb2d75d8cb6057e7e1b3c75cbbd5a5adc exploited BIGFI token contract 0xd3d4b46db01c006fb165879f343fc13174a1ceeb and its PancakeSwap pair 0xa269556edc45581f355742e46d2d722c5f3f551a. The adversary cluster consisted of EOA 0x76a88c2baebf251701435abbe8af11ad52b0ab04, which submitted the transaction and paid gas, and exploit contract 0x1a14ccc8f353d16582c0dfab907481b218475959, which executed the strategy.
The exploit borrowed 200000000000000000000000 USDT from public flash-loan pool 0x28ec0b36f0819ecb5005cab836f4ed5a2eca4d13, bought BIGFI, abused BIGFI's public burn(uint256) function to collapse nominal supply from 20999908387035301038246170 to 12800, called sync() on the Pancake pair, and then sold 3 BIGFI back into the manipulated pool for 230466095832979875922923 USDT. After repaying 200160000000000000000000 USDT to the flash-loan pool, the exploit contract retained 30306095832979875922923 USDT. The root cause is a unit-mismatch bug in : the function subtracts a token-denominated amount directly from a reflection-denominated balance and reduces without the matching adjustment.
DxBurnToken::_burn_tTotal_rTotalBIGFI is a reflection token. For non-excluded accounts, balances are not stored directly in token units. Instead, the token stores reflection balances in _rOwned, and balanceOf(account) returns tokenFromReflection(_rOwned[account]). The conversion rate is derived from _rTotal / _tTotal, so changing total nominal supply without a matching reflection adjustment changes every visible balanceOf result.
That design means the burn path has to preserve unit consistency. Burning x tokens should remove x * currentRate reflections from _rOwned, reduce _tTotal consistently, and keep the supply-side state coherent. BIGFI does not do that. Its public burn(uint256) path accepts any holder call and reaches a private _burn that directly compares a token amount to _rOwned and subtracts that same token amount from _rOwned.
The AMM leg matters because PancakePair 0xa269556edc45581f355742e46d2d722c5f3f551a updates reserves from live token balances when sync() is called. If BIGFI's balanceOf(pair) becomes false because reflection accounting is corrupted, the pair can be re-synced to a fictitious reserve ratio and then immediately drained through a normal swap.
This incident is an ATTACK-class ACT exploit caused by broken accounting in the victim token, not by a privileged action or off-chain secret. BIGFI's source stores balances in reflection units but exposes them as token units, which is standard for reflection tokens. The bug is that _burn takes a token-denominated input and uses it directly against _rOwned[_addr], even though _rOwned is reflection-denominated. That makes the guard require(_value <= _rOwned[_addr]) far weaker than the intended "caller owns at least _value tokens" condition. Once the attacker buys any meaningful BIGFI balance, their _rOwned value is orders of magnitude larger than their visible token balance, so they can burn an enormous nominal token amount they do not actually hold. Because _tTotal is reduced while _rTotal is not, the reflection rate spikes, balanceOf(pair) collapses, and PancakeSwap prices BIGFI against a false reserve ratio after sync(). The exploit is fully permissionless because all required calls are public: flashLoan, PancakeRouter swaps, BIGFI burn, and PancakePair sync.
The code-level breakpoint is the BIGFI _burn implementation:
function balanceOf(address account) public view override returns (uint256) {
if (_isExcluded[account]) return _tOwned[account];
return tokenFromReflection(_rOwned[account]);
}
function tokenFromReflection(uint256 rAmount) public view returns(uint256) {
require(rAmount <= _rTotal, "Amount must be less than total reflections");
uint256 currentRate = _getRate();
return rAmount.div(currentRate);
}
function _burn(address _addr, uint256 _value) private {
require(_value <= _rOwned[_addr]);
_rOwned[_addr] = _rOwned[_addr].sub(_value);
_tTotal = _tTotal.sub(_value);
emit Transfer(_addr, dead, _value);
}
Origin: verified BIGFI contract source.
Immediately before the exploit transaction, the public pre-state included three critical conditions: the flash-loan pool held ample USDT liquidity, the BIGFI/USDT Pancake pair held both USDT and BIGFI reserves, and BIGFI total supply was still the large pre-exploit value above 2.0999e25. The collected balance diff shows the exploit contract started the transaction with 0 USDT and ended with 30306095832979875922923 USDT, so the profit predicate is fully grounded in state changes rather than inference.
The exploit begins by borrowing 200000000000000000000000 USDT from SwapFlashLoan. That USDT is swapped through PancakeRouter into BIGFI, leaving the exploit contract with 5869494994603961621184 BIGFI and the pair with 3259991321231734828254 BIGFI according to the trace. At this point the attacker does not own the 20999908387035301038233370 BIGFI that they are about to burn in nominal units, but the broken _burn guard compares that value to _rOwned[attacker], not to balanceOf(attacker), so the call succeeds.
The critical accounting break happens here:
_burn subtracts the nominal input from _rOwned[attacker]._burn subtracts the same nominal input from _tTotal._burn does not reduce _rTotal.That combination sharply increases the ratio currentRate = rSupply / tSupply. Since balanceOf(account) returns _rOwned[account] / currentRate, every non-excluded reflected holder suddenly appears to own far fewer BIGFI tokens. The trace shows the pair's BIGFI balance dropping from 3259991321231734828254 to 1 immediately after the burn, while the attacker still controls 3 BIGFI. No transfer removed the pair's reflected balance; the visible balance changed because the reflection conversion was corrupted.
The trace captures the pivot from accounting corruption to pool drain:
DxBurnToken::burn(20999908387035301038233370)
emit Transfer(from: attacker_contract, to: 0x000000000000000000000000000000000000dEaD, value: 20999908387035301038233370)
DxBurnToken::balanceOf(PancakePair) -> 1
PancakePair::sync()
emit Sync(reserve0: 307480664198219600542112, reserve1: 1)
PancakeRouter::swapExactTokensForTokensSupportingFeeOnTransferTokens(3, 0, [BIGFI, USDT], attacker_contract, ...)
emit Transfer(from: PancakePair, to: attacker_contract, value: 230466095832979875922923)
Origin: collected seed trace for tx 0x9fe19093a62a7037d04617b3ac4fbf5cb2d75d8cb6057e7e1b3c75cbbd5a5adc.
After sync(), PancakePair stores reserves of 307480664198219600542112 USDT and 1 BIGFI. That false reserve ratio lets the attacker sell 3 BIGFI for 230466095832979875922923 USDT in a standard router swap. The flash loan is then repaid with the required 160000000000000000000 USDT fee, proving the sequence is self-contained and permissionless. The exploit contract finishes with 30306095832979875922923 USDT, while the sender EOA pays 3336685200000000 wei in gas, yielding a net adversary-cluster delta of 30305005883562115625965 USDT-equivalent under the valuation recorded in root_cause.json.
The adversary strategy is a single-transaction flash-loan-assisted reserve distortion and backswap.
SwapFlashLoan::flashLoan(attacker_contract, USDT, 200000000000000000000000, 0x00)
PancakeRouter::swapExactTokensForTokensSupportingFeeOnTransferTokens(USDT -> BIGFI)
DxBurnToken::burn(20999908387035301038233370)
PancakePair::sync()
PancakeRouter::swapExactTokensForTokensSupportingFeeOnTransferTokens(BIGFI -> USDT)
BEP20USDT::transfer(SwapFlashLoan, 200160000000000000000000)
Origin: collected seed trace for the exploit transaction.
The transaction sender was EOA 0x76a88c2baebf251701435abbe8af11ad52b0ab04. The exploit logic ran inside contract 0x1a14ccc8f353d16582c0dfab907481b218475959, which received the flash loan, performed the swaps, called the vulnerable burn, synchronized the pair, and retained the profit.
Step-by-step, the flow is:
SwapFlashLoan.flashLoan transfers 200000000000000000000000 USDT to the exploit contract and expects 200160000000000000000000 USDT back.0x10ed43c718714eb63d5aa57b78b54704e256024e and swaps the borrowed USDT into BIGFI.totalSupply, balanceOf(pair), and balanceOf(self) to derive a target supply that leaves the pair with one visible BIGFI and the attacker with at least three visible BIGFI after the broken burn.burn with 20999908387035301038233370, which is enough to collapse BIGFI total supply to 12800.sync(), fixing the manipulated visible balances as official reserves.3 BIGFI back into USDT, withdrawing 230466095832979875922923 USDT from the pair.30306095832979875922923 USDT.This sequence is feasible for any unprivileged actor because every call target in the transaction is public and the exploit requires only chain-observable state plus temporary liquidity.
The measurable victim-side loss is the USDT drained from the BIGFI/USDT Pancake pair. The collected balance diff shows the pair's USDT balance decreased from 107480664198219600542112 to 77014568365239724619189, a loss of 30466095832979875922923 USDT units. BIGFI reserves were also corrupted: the pair's visible BIGFI reserve ended at 4, leaving the market permanently mispriced and effectively drained of usable liquidity.
The exploit contract retained 30306095832979875922923 USDT after the flash-loan repayment, and the flash-loan pool earned 160000000000000000000 USDT in fees. Gas paid by the sender EOA was 3336685200000000 wei, which the updated root-cause artifact values at 1089949417760296958 USDT-equivalent using the on-chain USDT/WBNB pair at the exploit block. On a net basis, the adversary cluster realized 30305005883562115625965 USDT-equivalent profit.
0x9fe19093a62a7037d04617b3ac4fbf5cb2d75d8cb6057e7e1b3c75cbbd5a5adc0xd3d4b46db01c006fb165879f343fc13174a1ceeb0xa269556edc45581f355742e46d2d722c5f3f551a0x28ec0b36f0819ecb5005cab836f4ed5a2eca4d130x10ed43c718714eb63d5aa57b78b54704e256024e