Calculated from recorded token losses using historical USD prices at the incident time.
0xa0408770d158af99a10c60474d6433f4c20f3052e54423f4e590321341d4f2a40xedecfa18cae067b2489a2287784a543069f950f4BSC0x779a0e4799488d2fcac65f5fb8eb65dbbf08ce43BSCOn BNB Chain block 36725820, transaction 0xa0408770d158af99a10c60474d6433f4c20f3052e54423f4e590321341d4f2a4 realized a permissionless reserve-drain against the TGBS/WBNB PancakePair at 0x779a0e4799488d2fcac65f5fb8eb65dbbf08ce43. The adversary EOA 0xff1db040e4f2a44305e28f8de728dabff58f01e1 deployed exploit contract 0x3eba5062ca36dfb16156748f0fd3a608be9e3011, borrowed WBNB from public lender 0x05d968b7101701b6ad5a69d45323746e9a791eb5, bought TGBS, repeatedly self-transferred 1 TGBS to trigger pair-side burning, then dumped TGBS back into the manipulated pool and exited with 366806293729560708961 WBNB before gas.
The root cause is a token-level logic flaw in TGBS, not a PancakeSwap bug. TGBS ordinary transfers can call _burnPool(), and _burnPool() burns TGBS directly from the pair with super._burn(_swapPair, burnAmount) and immediately commits the lower balance into the AMM reserves with ISwapPair(_swapPair).sync(). Because _burnBlock only advances by 1200 per call, an unprivileged holder can repeat this reserve destruction many times inside one transaction and then sell into the skewed pool for profit.
The victim token is TGBS at 0xedecfa18cae067b2489a2287784a543069f950f4, paired against WBNB on PancakeSwap. PancakePair pricing depends on its tracked reserves, and forces those reserves to match the pair's current token balances. If one token is burned directly from the pair while the paired asset stays unchanged, the reserve ratio is distorted and the pool price moves.
sync()TGBS embeds tokenomics logic in _transfer(). The verified source shows four relevant branches: exempt transfers, buys from _swapPair, sells to _swapPair, and ordinary wallet-to-wallet transfers. Ordinary transfers fall through to super._transfer(from, to, amount); _burnPool();, so arbitrary users can reach _burnPool() even when they are not interacting with the pair directly.
The pair-side behavior is standard PancakeSwap behavior. swap() pays out assets against the current reserves, and sync() updates those reserves to the pair's current balances:
function sync() external lock {
_update(IERC20(token0).balanceOf(address(this)), IERC20(token1).balanceOf(address(this)), reserve0, reserve1);
}
That means any token contract that can directly change the pair's balances and then call sync() can reprice the pool.
The vulnerability class is an ATTACK-type logic flaw: TGBS grants arbitrary transfers authority to destroy pair-owned inventory and re-anchor AMM reserves to the attacker-selected post-burn state. The verified TGBS code shows the full path. In _transfer(), ordinary transfers call _burnPool() at line 905, and sells call _burnPool() at line 897 before forwarding the seller's tokens into the pair. In _burnPool(), if _burnBlock < block.number && _burnBlock > 0, the contract increments _burnBlock by 28800 / 24, computes burnAmount = (balanceOf(_swapPair) * 3) / 1000, burns that amount from the pair, and then calls sync().
function _burnPool() private lockTheSwap returns (bool) {
if (_burnBlock < block.number && _burnBlock > 0) {
_burnBlock += 28800 / 24;
uint256 burnAmount = (balanceOf(_swapPair) * 3) / 1000;
if (burnAmount > 1) {
super._burn(_swapPair, burnAmount);
try ISwapPair(_swapPair).sync() {} catch {}
emit BurnPool(burnAmount);
return true;
}
}
return false;
}
The violated invariant is: unprivileged token transfers must not be able to destroy AMM-owned tokens and reprice the pool without contributing the paired asset. The concrete breakpoint is super._burn(_swapPair, burnAmount) followed by ISwapPair(_swapPair).sync() in TGBS._burnPool().
The exploit is fully reconstructible from public state immediately before block 36725820. The pair held both WBNB and TGBS liquidity, _burnBlock was non-zero and still below the live block number, and the public lender held enough WBNB for a flashloan. No privileged roles, private keys, or off-chain secrets were needed.
The transaction trace shows the exploit contract first receiving 1229936096619139548461 WBNB from the lender, then buying 2151058483426887748122238 TGBS through PancakeSwap. After that buy, the trace enters a long sequence of TGBS::transfer(..., 1) calls from the exploit contract to itself, each immediately followed by PancakePair::sync(). This exactly matches the _transfer() -> _burnPool() path in the verified TGBS source.
The important property is that each self-transfer changes only the pair's TGBS side. _burnPool() burns 0.3% of the pair's current TGBS balance but does not remove any WBNB. sync() then commits the lower TGBS balance as the official reserve state. Repeating this thousands of times collapses the TGBS reserve while keeping the WBNB reserve largely intact, so the pool price moves sharply in favor of TGBS sellers.
The balance-diff artifact confirms the reserve destruction and the final drain. The pair's TGBS balance fell from 2820781743014684189121858 to 1946858775346490905890064, a net decrease of 873922967668193283231794 TGBS during the transaction. The final trace segment then shows PancakePair::swap(1596742390348700257422, 0, ...), transferring 1596742390348700257422 WBNB to the exploit contract, followed by repayment of 1229936096619139548461 WBNB to the lender and a final transfer of 366806293729560708961 WBNB to the adversary EOA.
The resulting execution is deterministic: public flash liquidity funds the initial buy, the transfer hook repeatedly destroys pair reserves, and the attacker realizes profit by dumping into the manipulated pool before repaying the flashloan.
The adversary flow consists of a single adversary-crafted transaction.
0xff1db040e4f2a44305e28f8de728dabff58f01e1 deploys exploit contract 0x3eba5062ca36dfb16156748f0fd3a608be9e3011.1229936096619139548461 WBNB from lender 0x05d968b7101701b6ad5a69d45323746e9a791eb5.0x10ed43c718714eb63d5aa57b78b54704e256024e.1 TGBS, causing _burnPool() to burn pair-owned TGBS and call sync() after each burn._burnBlock catches up to the live block, it sells its TGBS inventory back into the now-skewed pair and extracts WBNB.Representative trace evidence:
WBNB::transfer(0x3eBA5062ca36DFB16156748f0fD3A608Be9E3011, 1229936096619139548461)
PancakePair::swap(0, 2151058483426887748122238, 0x3eBA5062ca36DFB16156748f0fD3A608Be9E3011, 0x)
TGBS::transfer(0x3eBA5062ca36DFB16156748f0fD3A608Be9E3011, 1)
PancakePair::sync()
...
PancakePair::swap(1596742390348700257422, 0, 0x3eBA5062ca36DFB16156748f0fD3A608Be9E3011, 0x)
WBNB::transfer(0x05d968B7101701b6AD5a69D45323746E9a791eB5, 1229936096619139548461)
WBNB::transfer(0xFF1db040e4f2a44305E28f8dE728DABFF58f01E1, 366806293729560708961)
This flow is ACT-complete because every step uses public contracts and public state: the lender is permissionless, the pair is public liquidity, and the reserve-destruction primitive is reachable from ordinary transfers by any holder.
The direct measured loss is 366806293729560708961 WBNB of net adversary profit, with 18 decimals. The affected public components are the TGBS token contract and the TGBS/WBNB PancakePair, whose reserve integrity was broken by TGBS's transfer hook.
The broader impact is that TGBS converted a tokenomics helper into a permissionless AMM manipulation primitive. Any attacker able to acquire TGBS and submit a transaction while _burnBlock lagged the block number could force destructive reserve updates and extract value from the pool.
0xa0408770d158af99a10c60474d6433f4c20f3052e54423f4e590321341d4f2a40xff1db040e4f2a44305e28f8de728dabff58f01e10x3eba5062ca36dfb16156748f0fd3a608be9e30110xedecfa18cae067b2489a2287784a543069f950f40x779a0e4799488d2fcac65f5fb8eb65dbbf08ce430x05d968b7101701b6ad5a69d45323746e9a791eb5tgbs.solContract.sol