BlackGold Reserve Collapse
Exploit Transactions
0xea108fe94bfc9a71bb3e4dee4a1b0fd47572e6ad6aba8b2155ac44861be628aeVictim Addresses
0xc2319e87280c64e2557a51cb324713dd8d1410a3BSC0x7526cc9121ba716cec288af155d110587e55df8bBSC0x429339fa7a2f2979657b25ed49d64d4b98a2050dBSCLoss Breakdown
Similar Incidents
CFC Reserve Collapse
48%Sheep Burn Reserve Drain
41%CoinToken Burn Supply Collapse
40%9419 Migration Arbitrage
38%PLTD reserve-burn exploit
36%CoinToken Burn Reserve Drain
36%Root Cause Analysis
BlackGold Reserve Collapse
1. Incident Overview TL;DR
At BNB Chain block 23844530, transaction 0xea108fe94bfc9a71bb3e4dee4a1b0fd47572e6ad6aba8b2155ac44861be628ae let an unprivileged adversary drain value from the old BlackGold liquidity pools on PancakeSwap and exit with 18476301570841399595201 USDT. The adversary EOA 0xf4fd2ebe7196c8e99e88bcc4aef69dda0e493b8f invoked exploit contract 0x56b2b04e5cea5274fc5f79d648ea7da739a50b41, borrowed public flash liquidity, collapsed the old BlackGold reserves in the BlackGold/WBNB pair 0x7526cc9121ba716cec288af155d110587e55df8b and the BlackGold/DEBT pair 0x429339fa7a2f2979657b25ed49d64d4b98a2050d, migrated residual old BlackGold through the public migration contract 0xe445654f3797c5ee36406dbe88fbaa0dfbddb2bb, then sold through DEBT into USDT.
The root cause is a deterministic accounting flaw in old BlackGold 0xc2319e87280c64e2557a51cb324713dd8d1410a3. Its _transfer implementation debits a non-excluded sender by amount + 4% mining fee + 4% liquidity fee + 2% burn fee, while still crediting the recipient with the full amount. When a PancakePair is not fee-excluded, every pair-originated transfer during swap and skim silently destroys pool inventory outside the AMM's expected accounting model. That mismatch lets an attacker use public swap, transfer, skim, and sync calls to collapse reserves to near zero and drain the paired asset.
2. Key Background
Three protocol facts are necessary to understand the incident.
First, PancakePair assumes token transfers are balance-preserving from the pool's perspective: when the pair sends amount, the pair balance should fall by exactly amount, and reserves should continue to represent spendable inventory that backs the constant-product invariant.
Second, old BlackGold applies hidden fees when neither sender nor recipient is excluded. The verified source shows 4% mining fee, 4% liquidity fee, and 2% burn fee inside _transfer, with the recipient still receiving the full transfer amount.
uint256 burnFee = onePercent.mul(2);
uint256 miningFee = onePercent.mul(4);
uint256 liquidityFee = onePercent.mul(4);
_balances[sender] = _balances[sender].sub(amount, "BEP20: transfer amount exceeds balance");
_balances[recipient] = _balances[recipient].add(amount);
if (!_isExcludedFromFee[sender] && !_isExcludedFromFee[recipient]) {
_balances[sender] = _balances[sender].sub(miningFee, "BEP20: miningFee amount exceeds balance");
_balances[sender] = _balances[sender].sub(liquidityFee, "BEP20: liquidityFee amount exceeds balance");
_burn(sender, burnFee);
}
Third, PancakePair exposes public skim and sync functions. skim sends any token balance above recorded reserves to an arbitrary address, and sync updates reserves to current balances. Those functions are safe only when the token's accounting matches ERC-20 transfer expectations.
3. Vulnerability Analysis & Root Cause Summary
This incident is an ATTACK-class ACT exploit against BlackGold's transfer accounting, not an MEV-only event. The violated invariant is straightforward: for a token integrated with PancakePair, a pair-originated transfer of amount must reduce the pair's balance by exactly amount. Old BlackGold breaks that invariant whenever the pair is not fee-excluded.
The code-level breakpoint is old BlackGold _transfer, where the sender is first debited by amount, the recipient is credited by amount, and then the sender is further debited by mining, liquidity, and burn fees if neither side is excluded. For a PancakePair sender, the pool therefore loses amount + 10% while the counterparty still receives amount.
That flaw makes the sequence swap -> attacker transfer back to pair -> skim -> sync a deterministic reserve-collapse primitive. The pair's spendable token inventory falls faster than the reserves model expects, skim triggers a second pair-originated hidden-fee debit, and sync finalizes the near-zero reserve state. Once reserves are collapsed, selling even 100000000 old BlackGold drains the paired asset almost completely.
The public migration contract increases realized value but is not the exploit primitive. The exploit primitive is the reserve collapse caused by incompatible fee-on-transfer accounting in old BlackGold.
4. Detailed Root Cause Analysis
4.1 ACT opportunity definition
The ACT pre-state is the publicly reconstructible BNB Chain state immediately before the seed transaction, including:
- the old BlackGold token
0xc2319e87280c64e2557a51cb324713dd8d1410a3, - the replacement BlackGold token
0x169f715cae1f94c203366a6890053e817c767b7c, - the DEBT token
0xc632f90affec7121120275610bf17df9963f181c, - the old BlackGold/WBNB pair
0x7526cc9121ba716cec288af155d110587e55df8b, - the old BlackGold/DEBT pair
0x429339fa7a2f2979657b25ed49d64d4b98a2050d, - the migration contract
0xe445654f3797c5ee36406dbe88fbaa0dfbddb2bb.
An unprivileged adversary can reproduce the attack because every required step uses public code paths: DPP flash liquidity, PancakePair swaps, skim, sync, router swaps, and the migration contract are all permissionless.
4.2 Reserve collapse in the old BlackGold/WBNB pair
The seed trace shows the exploit contract borrowing 125000000000000000000 WBNB from DPP 0x0fe261aee0d1c4dfddee4102e82dd425999065f4, transferring it into the old BlackGold/WBNB pair, and calling swap to buy old BlackGold. The attacker then transferred old BlackGold back to the pair, called skim, added 100 old BlackGold, and called sync.
The trace records the key pair interactions:
PancakePair::swap(0, 196793118115183, 0x56B2...50b41, 0x)
PancakePair::skim(0x56B2...50b41)
PancakePair::sync()
PancakeRouter::swapExactTokensForTokensSupportingFeeOnTransferTokens(
100000000,
0,
[old BlackGold, WBNB],
0x56B2...50b41,
...
)
PancakePair::swap(133795673964608992251, 0, 0x56B2...50b41, 0x)
emit Sync(reserve0: 138154931512329, reserve1: 100000103)
This is the observable manifestation of the invariant break. During pair-originated transfers in swap and again in skim, the pair loses more old BlackGold than the AMM model expects. After the attacker tops the pair up by 100 and calls sync, the pool is left with only 100000103 old BlackGold against 138154931512329 residual WBNB. Selling 100000000 old BlackGold then drains 133795673964608992251 WBNB.
The balance diff independently confirms the state change:
{
"token": "0xc2319e87280c64e2557a51cb324713dd8d1410a3",
"holder": "0x7526cc9121ba716cec288af155d110587e55df8b",
"before": "231743012965866",
"after": "100000103",
"delta": "-231742912965763"
}
4.3 Reserve collapse in the old BlackGold/DEBT pair
The attacker repeated the same primitive against the old BlackGold/DEBT pair after taking a 950000000000 DEBT flash swap from the replacement-token/DEBT pair 0x559d0deacad259d970f65be611f93fccd1c44261.
The trace shows the same structure:
0x559D...4261::swap(0, 950000000000, 0x56B2...50b41, 0x21)
PancakePair::swap(179669913939965, 0, 0x56B2...50b41, 0x)
PancakePair::skim(0x56B2...50b41)
PancakePair::sync()
PancakeRouter::swapExactTokensForTokensSupportingFeeOnTransferTokens(
100000000,
0,
[old BlackGold, DEBT],
0x56B2...50b41,
...
)
PancakePair::swap(0, 1048941583051, 0x56B2...50b41, 0x)
emit Sync(reserve0: 100000103, reserve1: 1083118)
After collapse, the old BlackGold/DEBT pair retains only 100000103 old BlackGold and 1083118 DEBT. The balance diff matches those end-state balances exactly.
4.4 Migration and exit path
Once the attacker had extracted WBNB and DEBT from the old-token pools, the exploit called the public migration contract twice. The trace shows 0xE445654F3797c5Ee36406dBe88FBAA0DfbdDB2Bb::migrate() followed by sales of replacement BlackGold into DEBT and then DEBT into USDT.
The root-cause evidence shows:
- residual old BlackGold was migrated into replacement BlackGold,
175249555599300replacement BlackGold was sold for70948154990DEBT,- the final
167419738041DEBT was swapped through the DEBT/USDT pair0xbe46815e0f0123ad626b82a0166eaa32274104f5, - the adversary EOA received
18476301570841399595201USDT.
The balance diff confirms final settlement:
{
"token": "0x55d398326f99059ff775485246999027b3197955",
"holder": "0xf4fd2ebe7196c8e99e88bcc4aef69dda0e493b8f",
"before": "0",
"after": "18476301570841399595201",
"delta": "18476301570841399595201"
}
The same artifact records -30002800000000000 wei of BNB as gas paid by the adversary EOA. The transaction sequence is therefore complete, deterministic, and publicly reproducible from the collected evidence alone.
5. Adversary Flow Analysis
The adversary strategy is a single-transaction, multi-stage reserve-collapse attack.
- The EOA
0xf4fd2ebe7196c8e99e88bcc4aef69dda0e493b8fsends the seed transaction to exploit contract0x56b2b04e5cea5274fc5f79d648ea7da739a50b41. - The exploit contract obtains public flash liquidity:
125WBNB from DPP and later950000000000DEBT from the replacement-token/DEBT pair. - The contract buys old BlackGold from the old BlackGold/WBNB pair, transfers most of the purchased tokens back into the pair, calls
skim, adds100, and callssyncto lock in a near-zero old BlackGold reserve. - The contract sells
100000000old BlackGold back into the collapsed WBNB pair and extracts133795673964608992251WBNB. - The same reserve-collapse pattern is repeated against the old BlackGold/DEBT pair, extracting
1048941583051DEBT from a100000000old BlackGold sale. - The contract uses the public migration contract to convert residual old BlackGold into replacement BlackGold, sells replacement BlackGold into DEBT, then sells the remaining DEBT into USDT through the DEBT/USDT pair.
- The transaction ends with the adversary EOA holding
18476301570841399595201USDT.
The identified adversary-related accounts are:
- EOA
0xf4fd2ebe7196c8e99e88bcc4aef69dda0e493b8f, which sent the transaction, received final USDT, and paid gas. - Contract
0x56b2b04e5cea5274fc5f79d648ea7da739a50b41, which executed the exploit flow, handled flash liquidity, and interacted with pairs and migration contracts.
Victim-side components implicated in the exploit are:
- old BlackGold
0xc2319e87280c64e2557a51cb324713dd8d1410a3, - old BlackGold/WBNB pair
0x7526cc9121ba716cec288af155d110587e55df8b, - old BlackGold/DEBT pair
0x429339fa7a2f2979657b25ed49d64d4b98a2050d.
6. Impact & Losses
The measurable realized loss captured in the evidence is 18476301570841399595201 USDT (18 decimals) credited to the adversary EOA. The drained value originated from the old BlackGold/WBNB and old BlackGold/DEBT liquidity pools and was converted through public migration and swap paths into the final stablecoin output.
The old-token pools were left in a depleted state:
- old BlackGold/WBNB pair balance:
100000103old BlackGold and138154931512329WBNB, - old BlackGold/DEBT pair balance:
100000103old BlackGold and1083118DEBT.
The security impact is broader than the final USDT figure. Any non-excluded PancakePair holding old BlackGold was exposed to the same reserve-collapse primitive because the flaw is in the token's transfer semantics rather than in any attacker-specific artifact.
7. References
- Seed transaction metadata for
0xea108fe94bfc9a71bb3e4dee4a1b0fd47572e6ad6aba8b2155ac44861be628ae. - Seed transaction trace showing the flash loan, pair
swap,skim,sync, migration, and exit swaps. - Seed transaction balance diff showing pair depletion, adversary gas payment, and final USDT profit.
- Verified old BlackGold source at
0xc2319e87280c64e2557a51cb324713dd8d1410a3, especially_transferand fee-exclusion handling. - Verified replacement BlackGold source at
0x169f715cae1f94c203366a6890053e817c767b7c. - Verified DEBT source at
0xc632f90affec7121120275610bf17df9963f181c.