Calculated from recorded token losses using historical USD prices at the incident time.
0x7f183df11f1a0225b5eb5bb2296b5dc51c0f3570e8cc15f0754de8e6f8b4cca40x2287c04a15bb11ad1358ba5702c1c95e2d13a5e0BSC0x8aff4e8d24f445df313928839ec96c4a618a91c8BSCOn BSC block 19523981, transaction 0x7f183df11f1a0225b5eb5bb2296b5dc51c0f3570e8cc15f0754de8e6f8b4cca4 realized a deterministic anyone-can-take exploit against SpaceGodzilla (0x2287c04a15bb11ad1358ba5702c1c95e2d13a5e0). The attacker used a flashloan-backed contract to call public maintenance hooks that spend SpaceGodzilla-owned balances, reset a public helper latch that controls buy-side transfer reduction, and then spoofed the token’s add-liquidity detector with a 20000-wei USDT dust transfer before selling back into the same Pancake pair. The attacker EOA 0x00a62eb08868ec6feb23465f61aa963b89e57e57 ended the transaction with 25378755321988456881827 more USDT, while the SpaceGodzilla contract lost 30378842175602511050329 USDT-equivalent balance from its own holdings.
The root cause is a compound victim-side ATTACK bug. SpaceGodzilla exposed swapTokensForOther(uint256) and swapAndLiquifyStepv1() as public functions even though they spend protocol-owned balances; the external warp helper exposed a public priceInit() that rewrites the buy-path gas-price latch inside the same attacker transaction; and _isAddLiquidityV1() treated a small pair-balance surplus as proof of a legitimate liquidity add, which let the attacker suppress the intended sell fee.
SpaceGodzilla is a fee-on-transfer token on BSC that routes trading through the Pancake pair 0x8aff4e8d24f445df313928839ec96c4a618a91c8 against USDT . The token’s path applies custom logic on buys and sells. When tokens move from the pair, the token consults before completing the transfer. When tokens move to the pair, the token checks and can disable fees when it believes the transfer is part of a liquidity addition.
0x55d398326f99059ff775485246999027b3197955_transferwarp.warpToken(amount)_isAddLiquidityV1()The token also accumulates SGODZ and USDT-related balances on address(this). Those balances are supposed to support internal maintenance flows such as selling SGODZ for the base asset and pairing assets for liquidity adds. In the deployed contract, however, the functions that consume those balances are not access controlled.
The external warp helper at 0x8afd2be03147a3b05f430a3652088b049b32b373 is unverified, but its runtime behavior can still be recovered from bytecode, selector analysis, and storage diffs. The validator-confirmed helper analysis shows that priceInit() stores tx.gasprice into slot 0x0d, and warpToken(uint256) compares the current gas price to that slot to decide whether to return the full amount or a heavily reduced amount. The focused helper state diff for the exploit transaction shows that slot 0x0d changed from 7 gwei to 15 gwei, matching the exploit transaction’s gas price.
The incident is not a pure market-arbitrage event. It depends on three code-level failures in the victim system that an unprivileged actor can compose in one transaction. First, SpaceGodzilla lets any caller invoke reserve-management paths that spend balances owned by the token contract itself. Second, the helper state used to control buy-path reduction is mutable through a public function and can be rewritten immediately before the attacker buy. Third, the sell-fee suppression logic trusts a pair reserve delta heuristic rather than verifying actual liquidity mint semantics, so a trivial dust transfer can spoof the condition.
The violated invariant is straightforward: only protocol-controlled logic should spend SpaceGodzilla-owned balances, buy-path anti-bot state must not be reset by an arbitrary caller inside the exploit transaction, and sell-fee exemption must only trigger during genuine liquidity adds. The code-level breakpoints are swapTokensForOther(uint256) and swapAndLiquifyStepv1() being public, the helper’s public priceInit() mutating slot 13, and _isAddLiquidityV1() using bal1 - r1 > 1000 or bal0 - r0 > 1000 as its only decision rule.
The relevant victim code is explicit:
function _transfer(address from, address to, uint256 amount) internal override {
bool isAddLdx;
if (to == uniswapV2Pair) {
isAddLdx = _isAddLiquidityV1();
}
if (_isExcludedFromFees[from] || _isExcludedFromFees[to] || isAddLdx) {
takeFee = false;
} else {
if (from == uniswapV2Pair) {
amount = warp.warpToken(amount);
} else if (to == uniswapV2Pair) {
warp.addTokenldx(amount);
} else {
takeFee = false;
}
}
}
function swapTokensForOther(uint256 tokenAmount) public { ... }
function swapAndLiquifyStepv1() public { ... }
The liquidity detector is equally weak:
function _isAddLiquidityV1() internal view returns (bool ldxAdd) {
(uint r0, uint r1,) = IUniswapV2Pair(address(uniswapV2Pair)).getReserves();
uint bal1 = IERC20(token1).balanceOf(address(uniswapV2Pair));
if (token0 == address(this)) {
if (bal1 > r1) {
uint change1 = bal1 - r1;
ldxAdd = change1 > 1000;
}
}
}
These sites explain the exploit sequence end to end. In the seed trace, the attacker first called the helper’s public priceInit(), and the helper storage diff shows slot 13 changing from 0x1a13b8600 (7 gwei) to 0x37e11d600 (15 gwei). That neutralized the buy-path reduction for the subsequent pair buy. The same trace then shows a public call to SpaceGodzilla::swapTokensForOther(69127461036369179405415017714), which caused the token contract to transfer its own SGODZ inventory into the pair and move the price materially against future buyers.
Human-labeled excerpt from the exploit trace:
0x8AfD2be03147a3b05f430A3652088b049B32b373::priceInit()
storage slot 13: 0x...01a13b8600 -> 0x...037e11d600
SpaceGodzilla::swapTokensForOther(69127461036369179405415017714)
emit Transfer(from: SpaceGodzilla, to: SGODZ/USDT Pair, amount: 69127461036369179405415017714)
After that reserve reshaping, the attacker bought SGODZ from the pair while the refreshed helper latch allowed the full amount through the buy path. Later in the same transaction, the attacker transferred 20000 wei of USDT into the pair before selling back the purchased SGODZ. Because _isAddLiquidityV1() only checks whether the pair’s live USDT balance exceeds the stored reserve by more than 1000, this dust donation caused the function to return true. The result was a fee-free transfer of the attacker’s full SGODZ balance into the pair.
The decisive sell-side trace fragment is:
BEP20USDT::balanceOf(SGODZ/USDT Pair) -> reserve + 20000
emit Transfer(from: attacker_contract, to: SGODZ/USDT Pair, amount: 71562167863336388351131715170010)
0x8AfF4e8d24F445Df313928839eC96c4A618a91C8::swap(
amount0In = 71562167863336388351131715170010,
amount1In = 20000,
amount1Out = 2978176485325154862214560
)
The balance diff closes the loop: the attacker EOA gained 25378755321988456881827 USDT, the token contract lost 30378842175602511050329 USDT, and the pair retained the remainder created by the manipulated round trip.
The adversary cluster consists of EOA 0x00a62eb08868ec6feb23465f61aa963b89e57e57 and attacker contract 0x3d817ea746edd02c088c4df47c0ece0bd28dcd72. The contract was deployed in transaction 0xa56d0f02f641c000d8a3a54b3d7611f4689761447e75b04b942ebae915f544ee, 30 blocks before the exploit, and then used to execute the full flashloan strategy in the seed transaction.
The observable exploit flow is:
priceInit() on the warp helper to rewrite the gas-price latch from 7 gwei to the current 15 gwei.swapTokensForOther() so SpaceGodzilla sells its own SGODZ inventory into the pair.warpToken() returns the full amount after the latch update.swapAndLiquifyStepv1() to consume more victim-owned balances through another public maintenance path.20000 wei of USDT into the pair so _isAddLiquidityV1() misclassifies the next sell as a liquidity-add path.2978176485325154862214560 USDT.The transaction sequence is feasible for any unprivileged actor because every critical call surface is public, the relevant code and state are reconstructible from public chain data, and the sequence requires no privileged keys or attacker-only artifacts.
The root-cause artifacts attribute the direct victim-side loss to SpaceGodzilla’s USDT holdings. The measured loss is:
0x2287c04a15bb11ad1358ba5702c1c95e2d13a5e0: 30378842175602511050329 USDT base units.0x00a62eb08868ec6feb23465f61aa963b89e57e57: 25378755321988456881827 USDT base units gained.The difference between victim loss and attacker profit remains in the manipulated trading path, including the pair state and the attacker’s deliberate 20000-wei dust transfer. The incident therefore caused a deterministic economic loss to the protocol-owned balances while demonstrating that the fee and reserve-management design was permissionlessly exploitable.
0x7f183df11f1a0225b5eb5bb2296b5dc51c0f3570e8cc15f0754de8e6f8b4cca40xa56d0f02f641c000d8a3a54b3d7611f4689761447e75b04b942ebae915f544eeartifacts/collector/seed/56/0x2287c04a15bb11ad1358ba5702c1c95e2d13a5e0/src/Contract.solartifacts/collector/iter_1/contract/56/0x8afd2be03147a3b05f430a3652088b049b32b373/analysis_summary.jsonartifacts/collector/iter_1/tx/56/0x7f183df11f1a0225b5eb5bb2296b5dc51c0f3570e8cc15f0754de8e6f8b4cca4/helper_state_diff_focused.jsonartifacts/collector/iter_1/tx/56/0x7f183df11f1a0225b5eb5bb2296b5dc51c0f3570e8cc15f0754de8e6f8b4cca4/helper_pair_call_slice_summary.jsonartifacts/collector/seed/56/0x7f183df11f1a0225b5eb5bb2296b5dc51c0f3570e8cc15f0754de8e6f8b4cca4/balance_diff.json