Calculated from recorded token losses using historical USD prices at the incident time.
0xc3b1b45e5784a8efececfc0be2e28247d3f49963BSC0x794ed5e8251c4a8d321ca263d9c0bc8ecf5fa1ffBSCOn BSC (chainid 56), an adversary-controlled helper contract 0xbfd7280b11466bc717eb0053a78675aed2c2e388 abused a publicly accessible mint function on ERC20 token 0xc3b1b45e5784a8efececfc0be2e28247d3f49963 to create a very large amount of that token. The helper then routed the freshly minted tokens through an AMM pair 0x794ed5e8251c4a8d321ca263d9c0bc8ecf5fa1ff, swapping them for a substantial quantity of a stablecoin-like ERC20 token 0x55d398326f99059ff775485246999027b3197955.
The root cause is a protocol-level bug in token 0xc3b1…: it exposes a publicly callable mint function (selector 0xa7c861da) that directly increases totalSupply and a chosen recipient’s balance without any access control. Any unprivileged caller can therefore mint arbitrary amounts of the token and use AMM liquidity pools to drain external collateral (here, stablecoin 0x55d3…) backing the pool.
The core exploit transaction is 0xc29c98da0c14f4ca436d38f8238f8da1c84c4b1ee6480c4b4facc4b81a013438 in block 4,428,0829, sent by EOA 0xce21c6e4fa557a9041fa98dff59a4401ef0a18ac to the helper contract. A follow-up withdrawal transaction 0xb3b5f67e80529b95aff2983932ee72b543ce29b2838d7166760c09ce760044bc moves the drained stablecoin from the helper back to the EOA.
0x794ed5e8251c4a8d321ca263d9c0bc8ecf5fa1ff exposes a Uniswap V2–style interface (events , ; functions , , , , , ). Collected ABI data and the exploit transaction’s receipt and trace confirm that it acts as a liquidity pool between token and stablecoin .0xb3b5f67e80529b95aff2983932ee72b543ce29b2838d7166760c09ce760044bcSyncTransfermintskimsynctoken0token1permit0xc3b1…0x55d3…0x10ed43c718714eb63d5aa57b78b54704e256024e behaves as a Uniswap V2 router: the call trace shows it querying reserves on the pair via selector 0x0902f1ac and invoking the pair with selector 0x022c0d9f as part of the swap path that trades minted 0xc3b1… for 0x55d3….0xc3b1b45e5784a8efececfc0be2e28247d3f49963 is ERC20-like, emitting standard Transfer and Approval events and including LayerZero- and owner-configuration functions. Critically, its function with selector 0xa7c861da directly increases totalSupply and a specified address’s balance without checking msg.sender against any owner or role, making minting effectively permissionless.0xbfd7280b11466bc717eb0053a78675aed2c2e388, deployed by EOA 0xce21…, exposes functions with selectors 0x09b8790a and 0xbfbaa190. Decompiled code shows 0x09b8790a orchestrating calls to the factory, token 0xc3b1…, router 0x10ed…, and AMM pair 0x794e… to perform the mint-and-swap, while 0xbfbaa190 reads the helper’s token balance with balanceOf (0x70a08231) and then calls the token’s transfer (0xa9059cbb) to send the entire balance to msg.sender.0xce21c6e4fa557a9041fa98dff59a4401ef0a18ac deploys helper contract 0xbfd7… in tx 0x2775abd1518de94a27b53260767ea5834c21fcaaff62ed93c618c96712ff7204, and then sends the exploit tx 0xc29c… and withdrawal tx 0xb3b5… to it within the same block range. Collected address txlists show this tight coupling between the EOA and its helper.0xc29c98da0c14f4ca436d38f8238f8da1c84c4b1ee6480c4b4facc4b81a013438 (block 4,428,0829) shows ERC20 balance changes consistent with minting a large supply of 0xc3b1…, sending it to the AMM pair, and receiving 0x55d3… into the helper contract. Balance-diff artifacts, the receipt’s Transfer logs, and the call trace all agree on the direction and approximate magnitude of these flows.The ACT opportunity is defined at block height B = 4,428,0828 on BSC (chainid 56), just before the exploit block. In this pre-state:
0xc3b1b45e5784a8efececfc0be2e28247d3f49963 has been deployed with a public mint function (0xa7c861da) that increases totalSupply and an arbitrary recipient’s balance without any access control.0x794ed5e8251c4a8d321ca263d9c0bc8ecf5fa1ff holds a liquidity pool between token 0xc3b1… and stablecoin-like token 0x55d398326f99059ff775485246999027b3197955.0x10ed43c718714eb63d5aa57b78b54704e256024e and factory 0xca143ce32fe78f1f7019d7d551a6402fc5350c73 are deployed and wired to the pair so that swaps between 0xc3b1… and 0x55d3… are possible.0xbfd7280b11466bc717eb0053a78675aed2c2e388 has already been deployed by EOA 0xce21c6e4fa557a9041fa98dff59a4401ef0a18ac and configured to target this token/pair/router combination.In this pre-state, the protocol has already embedded the critical invariant violation: the mint function on 0xc3b1… permits arbitrary third-party minting. No on-chain defense (such as an allowlist, owner-only modifier, or off-chain guardian) prevents an attacker from minting large supplies and dumping them into existing liquidity pools.
Decompiled code for token 0xc3b1… shows the problematic mint function corresponding to selector 0xa7c861da:
Decompiled mint function for token 0xc3b1…, showing arbitrary recipient minting with no caller access control (collected contract source, decompiled from on-chain bytecode for 0xc3b1…):
/// @custom:selector 0xa7c861da
/// @custom:signature Unresolved_a7c861da(uint16 arg0, address arg1, uint256 arg2, uint256 arg3) public
function Unresolved_a7c861da(uint16 arg0, address arg1, uint256 arg2, uint256 arg3) public {
require(arg0 == (uint16(arg0)));
require(arg1 == (address(arg1)));
require(!arg3 > 0xffffffffffffffff);
require(!(arg3 > 0xffffffffffffffff), "ERC20: mint to the zero address");
...
require(address(arg1), "ERC20: mint to the zero address");
require(!(totalSupply > ~(arg2)), "ERC20: mint to the zero address");
totalSupply = totalSupply + arg2;
address var_a = address(arg1);
storage_map_b[var_a] = arg2 + storage_map_b[var_a];
emit Transfer(0, address(arg1), arg2);
}
Key observations:
public and never checks msg.sender against owner, a minter role, or any other privileged set; it is therefore callable by any address.address arg1 and uint256 arg2, verifies only that arg1 is not the zero address and that the mint does not overflow, then adds arg2 to totalSupply and to arg1’s balance, emitting a Transfer(0, arg1, arg2) event.arg2, no per-address limit, and no linkage to any on-chain collateral or locking mechanism.This is a textbook unrestricted mint vulnerability: any unprivileged address can mint unbounded token supply to itself or a helper contract.
Given a liquid AMM pool between the vulnerable token 0xc3b1… and stablecoin 0x55d3…, an attacker can:
0xc3b1… into an address they control (here, the helper contract).0x55d3…, pushing the pool price to near-zero for 0xc3b1… while extracting valuable 0x55d3… reserves.The collected call trace for the exploit tx 0xc29c… shows exactly this pattern. A simplified excerpt of the debug_traceTransaction callTracer output illustrates the main calls:
Call trace excerpt for exploit tx 0xc29c…, showing factory query, unrestricted mint on 0xc3b1…, and router-mediated swap into 0x55d3… (callTracer result for tx 0xc29c… on BSC):
{
"to": "0xca143ce32fe78f1f7019d7d551a6402fc5350c73",
"input": "0xe6a43905000000000000000000000000c3b1b45e5784a8efececfc0be2e28247d3f4996300000000000000000000000055d398326f99059ff775485246999027b3197955"
}
{
"to": "0xc3b1b45e5784a8efececfc0be2e28247d3f49963",
"input": "0xa7c861da0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bfd7280b11466bc717eb0053a78675aed2c2e3880000000000000000000000000000000000000000000531e553441b2d50bac038..."
}
{
"to": "0x10ed43c718714eb63d5aa57b78b54704e256024e",
"input": "0x5c11d7950000000000000000000000000000000000000000000531e553441b2d50bac038..."
}
{
"to": "0x55d398326f99059ff775485246999027b3197955",
"input": "0x70a08231000000000000000000000000bfd7280b11466bc717eb0053a78675aed2c2e388"
}
From this trace and the transaction’s receipt/balance diff:
(0xc3b1…, 0x55d3…).0xc3b1… with selector 0xa7c861da, minting a large amount of 0xc3b1… to itself (0xbfd7…).0xc3b1… from the helper and executes a swap on the pair, after which the helper’s 0x55d3… balance is non-zero and the pair’s 0x55d3… reserves are decreased.The seed balance-diff analysis for tx 0xc29c… summarizes ERC20 transfer effects:
Seed balance diff for tx 0xc29c…, showing minted 0xc3b1… and drained 0x55d3… (derived from pre/post state diffs and ERC20 Transfer events):
{
"erc20_transfers": [
{
"token": "0xc3b1b45e5784a8efececfc0be2e28247d3f49963",
"from": "0x0000000000000000000000000000000000000000",
"to": "0xbfd7280b11466bc717eb0053a78675aed2c2e388",
"value": "6280255360077122982559800"
},
{
"token": "0xc3b1b45e5784a8efececfc0be2e28247d3f49963",
"from": "0xbfd7280b11466bc717eb0053a78675aed2c2e388",
"to": "0x794ed5e8251c4a8d321ca263d9c0bc8ecf5fa1ff",
"value": "6280255360077122982559800"
},
{
"token": "0x55d398326f99059ff775485246999027b3197955",
"from": "0x794ed5e8251c4a8d321ca263d9c0bc8ecf5fa1ff",
"to": "0xbfd7280b11466bc717eb0053a78675aed2c2e388",
"value": "31538624555626362308555"
}
]
}
These diffs match the receipt’s Transfer logs for:
0xc3b1… mint from 0x0 to 0xbfd7… and subsequent transfer from 0xbfd7… to 0x794e….0x55d3… transfer from 0x794e… (the pair) to 0xbfd7… (the helper).Together with the decompiled mint function, this establishes that the attacker exploited a public, unrestricted mint to inject synthetic 0xc3b1… into the AMM and extract real 0x55d3… collateral.
0xc3b1….0xa7c861da to a privileged minter role or remove it; additionally, downstream protocols should gate-list or risk-screen tokens with unrestricted mint capabilities before listing them in collateral-bearing pools.0x2775abd1518de94a27b53260767ea5834c21fcaaff62ed93c618c96712ff7204 (block 4,428,0781).0xce21c6e4fa557a9041fa98dff59a4401ef0a18ac.0xbfd7280b11466bc717eb0053a78675aed2c2e388. The constructor bytecode embeds references to the key protocol addresses, including 0x55d3… (USDT-like token), factory 0xca143c…, router 0x10ed…, and AMM-related contracts such as 0x4f31….contractAddress = 0xbfd7…, with the input data containing multiple hard-coded addresses matching the factory, router, and token addresses used later in the exploit.This stage prepares a reusable helper that centralizes exploit logic: minting via the vulnerable token, interacting with the AMM, and later withdrawing stolen tokens.
0xc29c98da0c14f4ca436d38f8238f8da1c84c4b1ee6480c4b4facc4b81a013438 (block 4,428,0829).0xce21… calling helper 0xbfd7….mint_and_swap.6,280,255,360,077,122,982,559,800 units of 0xc3b1… to itself using the unrestricted mint function 0xa7c861da, sends those tokens to the AMM pair 0x794e…, and receives 31,538,624,555,626,362,308,555 units of 0x55d3… from the pair, depleting its 0x55d3… reserves.The debug_traceTransaction callTracer and receipt logs together show:
0xbfd7… to factory 0xca143c… (0xe6a43905) that returns the pair address 0x794e… for (0xc3b1…, 0x55d3…).0xbfd7… to token 0xc3b1… with selector 0xa7c861da and arg1 = 0xbfd7…, arg2 = 0x0531e553441b2d50bac038 (the minted amount), immediately followed by ERC20 Transfer(0x0 → 0xbfd7…, value = 6280255360…9800) and Transfer(0xbfd7… → 0x794e…, value = 6280255360…9800) logs for 0xc3b1….0xbfd7… to router 0x10ed…, which:
0xc3b1… with selector 0x23b872dd to transfer the minted tokens from 0xbfd7… to the pair.0x0902f1ac.0x022c0d9f, producing a Transfer(0x794e… → 0xbfd7…) log on token 0x55d3… and a Swap-like event on the pair.The balance diff quoted earlier shows the net inventory change: the helper’s 0x55d3… balance increases by 31538624555626362308555 units, exactly matching the amount transferred out of the pair.
0xb3b5f67e80529b95aff2983932ee72b543ce29b2838d7166760c09ce760044bc (block 4,428,0859).0xce21… calling helper 0xbfd7….withdraw_call.0x55d3… to the EOA. This consolidates the stolen stablecoin into the adversary’s externally owned account.The helper’s decompiled withdraw function (selector 0xbfbaa190) implements a straightforward “withdraw all balance to caller” pattern:
Decompiled withdraw function on helper 0xbfd7…, showing balanceOf(this) followed by transfer(msg.sender, balance) (collected contract source, decompiled from on-chain bytecode for 0xbfd7…):
/// @custom:selector 0xbfbaa190
/// @custom:signature Unresolved_bfbaa190(uint256 arg0, address arg1) public payable
function Unresolved_bfbaa190(uint256 arg0, address arg1) public payable {
require(!arg0 > 0xffffffffffffffff);
require(arg1 == (address(arg1)));
address var_h = address(this);
(bool success, bytes memory ret0) = address(arg1).Unresolved_70a08231(var_h); // staticcall balanceOf(this)
...
address var_j = address(msg.sender);
(bool success, bytes memory ret1) = address(arg1).Unresolved_a9059cbb(var_j); // call transfer(msg.sender, balance)
}
The address-level txlist for 0xbfd7… shows tx 0xb3b5… with:
from = 0xce21…to = 0xbfd7…methodId = 0xbfbaa1900x55d3….This strongly supports the interpretation that 0xb3b5… is a withdrawal of the helper’s 0x55d3… balance to the adversary’s EOA. However, note the following limitation:
0xb3b5… are not present in the collected dataset, so the profit attribution for the adversary relies primarily on the helper’s decompiled code and the fact that the helper already held the stolen 0x55d3… balance after tx 0xc29c….0x794ed5e8251c4a8d321ca263d9c0bc8ecf5fa1ff loses 31,538,624,555,626,362,308,555 units of token 0x55d398326f99059ff775485246999027b3197955 to the helper contract 0xbfd7… during the exploit tx 0xc29c….0x55d3… becomes controlled by the adversary via helper 0xbfd7… and, subsequently, the EOA 0xce21… after the withdrawal tx 0xb3b5….0xc3b1… is inflated by 6,280,255,360,077,122,982,559,800 units, with that supply first held by the helper and then largely residing in the AMM pair as worthless collateral from the perspective of stablecoin liquidity providers.Decimals for these tokens are not explicitly provided in the artifacts; if 0x55d3… behaves like common 18-decimal ERC20 tokens, the nominal loss would be on the order of 31.5386e6 “whole units”, but this report confines itself to the raw on-chain units recorded in the evidence.
0xc3b1…/0x55d3… pool on 0x794e…, who suffer direct depletion of their 0x55d3… collateral.0xc3b1… as having a fixed or capped supply, or that uses it as collateral elsewhere, is exposed to dilution and price collapse due to the unbounded minting capability.0xc29c98da0c14f4ca436d38f8238f8da1c84c4b1ee6480c4b4facc4b81a013438 (includes balance_diff.json and associated metadata summarizing ERC20 transfers and native balance changes).0xc29c… (debug_traceTransaction callTracer output and receipt.json, containing detailed call stack and ERC20 Transfer/Swap logs).0xc3b1b45e5784a8efececfc0be2e28247d3f49963 (supporting identification of the unrestricted mint function and ERC20 behavior).0xbfd7280b11466bc717eb0053a78675aed2c2e388 (supporting reconstruction of the mint-and-swap orchestration and withdraw-to-caller pattern).0xce21… and helper contract 0xbfd7… (supporting lifecycle reconstruction: deployment, exploit invocation, and withdrawal).