We do not have a reliable USD price for the recorded assets yet.
0xf075c5c7ba59208c0b9c41afccd1f60da9ec9c37BSCOn BNB Chain, transaction 0xfa1ece5381b9e2b2b83cb10faefde7632ca411bb38dd6bafe1f1140b1360f6ae exploited the public SUTTokenSale contract at 0xF075c5C7BA59208c0B9c41afcCd1f60da9EC9c37. An unprivileged searcher first deployed helper contract 0x9Be508CE41ae5795E1eBc247101C40Da7D5742DB in transaction 0x427ab1bf2f50a1eca0695ee892d30bd3b0c92d0ed74a2a77ec45a5731c981323, then used that helper to borrow 10 WBNB from DODO, buy the entire SUT inventory from the sale contract, sell the SUT into PancakeV3, repay the loan, and forward the residual WBNB to profit recipient 0xc5001F60DB92aFcC23177A6c6B440A4226cb58Bf.
The root cause is a permissionless MEV/ACT exposure in the sale contract itself. SUTTokenSale.buyTokens(uint256) prices purchases as (_numberOfTokens / 1e18) * tokenPrice, so fractional tokens are transferred without being charged, and the contract also trusts a manually set fixed tokenPrice with no market-price guard. At block 30165901, the sale contract held 32663166885742087138 SUT and exposed tokenPrice() = 214224507283633242, which made the entire inventory publicly buyable for 6855184233076263744 wei and immediately resellable for 39848103957183926491 WBNB on PancakeV3.
SUTTokenSale is a simple public token-sale contract. Its admin can set a global tokenPrice, and any address can call buyTokens(uint256) as long as the payment check passes. The contract then transfers the requested token amount immediately.
The traded asset is SUT at 0x70E1bc7E53EAa96B74Fad1696C29459829509bE2. The public resale venue used in the incident is PancakeV3 SUT/WBNB pool 0xEBc4B13F574AE8eb68E61B3B21F3457AB2f1F2e4, routed through Pancake router 0x13f4EA83D0bd40E75C8222255bc855a974568Dd4. The working capital primitive is DODO flash liquidity from 0xFeAFe253802b77456B4627F8c2306a9CeBb5d681. All of these endpoints are public and permissionless.
The seed trace confirms that immediately before exploitation the sale still held 32663166885742087138 SUT, and the balance diff confirms that the sale lost exactly that amount in the exploit transaction. The same trace also shows the helper receiving 39848103957183926491 WBNB from PancakeV3 and later transferring 32992919724107662747 WBNB to the profit recipient after repaying the 10 WBNB flash loan.
This incident is an economic ACT opportunity, not an access-control break. The vulnerable logic is directly in SUTTokenSale, where the contract sells market-traded inventory at a stored fixed price and computes payment using only the whole-token portion of the requested amount. The relevant code is:
function buyTokens(uint256 _numberOfTokens) public payable {
uint256 _bnbvalue = (_numberOfTokens/1000000000000000000)*tokenPrice;
require(msg.value >= _bnbvalue);
require(tokenContract.balanceOf(address(this)) >= _numberOfTokens, "Not enough tokens");
require(tokenContract.transfer(msg.sender, _numberOfTokens), "Transfer failed");
tokensSold += _numberOfTokens;
}
This breaks the intended sale invariant: a public buyer should pay for the exact token amount received. Instead, _numberOfTokens / 1e18 floors away any fractional remainder before multiplication. In the incident pre-state, the sale inventory was 32.663166885742087138 SUT, but the contract charged for only 32 whole tokens. Combined with the stale fixed tokenPrice, the inventory became materially underpriced relative to the live PancakeV3 execution price. Because buyTokens is permissionless and transfer settlement is immediate, any searcher with capital or flash liquidity could realize the spread in one transaction.
The ACT pre-state existed at block 30165901, immediately before block 30165902 mined the exploit. Publicly observable state included:
SUTTokenSale inventory: 32663166885742087138 SUT.SUTTokenSale.tokenPrice(): 214224507283633242 wei.0xFeAFe253802b77456B4627F8c2306a9CeBb5d681.0xEBc4B13F574AE8eb68E61B3B21F3457AB2f1F2e4.The pricing defect is deterministic. For _numberOfTokens = 32663166885742087138, the contract computes:
floor(32663166885742087138 / 1e18) * 214224507283633242
= 32 * 214224507283633242
= 6855184233076263744 wei
That payment bought the full 32.663166885742087138 SUT inventory, including the unpaid fractional remainder. The seed execution trace records exactly that call:
0xF075c5C7BA59208c0B9c41afcCd1f60da9EC9c37::tokenPrice() -> 214224507283633242
0xF075c5C7BA59208c0B9c41afcCd1f60da9EC9c37::buyTokens{value: 6855184233076263744}(32663166885742087138)
The same trace then shows the helper swapping the acquired SUT through PancakeV3 and receiving 39848103957183926491 WBNB:
0x13f4EA83D0bd40E75C8222255bc855a974568Dd4::exactInputSingle(...)
WBNB::transfer(0x9Be508CE41ae5795E1eBc247101C40Da7D5742DB, 39848103957183926491)
After rewrapping leftover BNB, repaying the flash loan principal, and transferring the remaining WBNB, the helper ended with zero balances and the profit recipient EOA received 32992919724107662747 WBNB. The balance-diff artifact independently confirms that the sale contract gained 6855184233076263744 wei while its SUT balance dropped from 32663166885742087138 to 0.
The adversary flow has two adversary-crafted transactions and no privileged step.
In tx 0x427ab1bf2f50a1eca0695ee892d30bd3b0c92d0ed74a2a77ec45a5731c981323, EOA 0x547fb3db0f13eed5d3ff930a0b61ae35b173b4b5 deployed helper contract 0x9Be508CE41ae5795E1eBc247101C40Da7D5742DB. The collected creation data ties the helper to that EOA and shows the bytecode hardcoded both the profit recipient 0xc5001f60db92afcc23177a6c6b440a4226cb58bf and the relevant public protocol addresses.
In tx 0xfa1ece5381b9e2b2b83cb10faefde7632ca411bb38dd6bafe1f1140b1360f6ae, the same EOA called the helper. The helper borrowed 10 WBNB from the DODO pool, unwrapped it to BNB, queried the sale inventory and tokenPrice, then called buyTokens with the full inventory amount and the undercharged payment value.
The helper approved Pancake router 0x13f4EA83D0bd40E75C8222255bc855a974568Dd4 and sold all purchased SUT through the live PancakeV3 pool. The trace shows exactInputSingle returning 39848103957183926491 WBNB to the helper.
The helper wrapped leftover BNB back into WBNB, repaid exactly 10 WBNB to the DODO pool, and transferred the remaining 32992919724107662747 WBNB to the hardcoded beneficiary. The collected token-transfer history for 0xc5001f60db92afcc23177a6c6b440a4226cb58bf confirms the final WBNB receipt in the exploit transaction.
This sequence is ACT-complete: the opportunity depends only on public state, public contract interfaces, and permissionless market liquidity. No admin privilege, stolen key, or private orderflow is needed.
The direct victim is SUTTokenSale at 0xF075c5C7BA59208c0B9c41afcCd1f60da9EC9c37. It lost its entire remaining sale inventory in one transaction:
SUT: 32663166885742087138 raw units (32.663166885742087138 tokens at 18 decimals)The economic impact extends beyond the token outflow. The sale contract accepted only 6855184233076263744 wei for inventory that the public market immediately priced at 39848103957183926491 WBNB. The adversary cluster realized 32991859749776362747 BNB-equivalent net profit after accounting for 1059974331300000 wei of gas from the sender EOA.
0xfa1ece5381b9e2b2b83cb10faefde7632ca411bb38dd6bafe1f1140b1360f6ae, sender 0x547fb3db0f13eed5d3ff930a0b61ae35b173b4b5, helper 0x9Be508CE41ae5795E1eBc247101C40Da7D5742DB.0xfa1ece5381b9e2b2b83cb10faefde7632ca411bb38dd6bafe1f1140b1360f6ae, showing tokenPrice(), buyTokens, PancakeV3 exactInputSingle, flash-loan repayment, and final WBNB profit transfer.0xfa1ece5381b9e2b2b83cb10faefde7632ca411bb38dd6bafe1f1140b1360f6ae, confirming sale-native inflow and full SUT inventory drain.SUTTokenSale source at 0xF075c5C7BA59208c0B9c41afcCd1f60da9EC9c37, especially settokenPrice(uint256) and buyTokens(uint256).0x9Be508CE41ae5795E1eBc247101C40Da7D5742DB, tying it to deployer 0x547fb3db0f13eed5d3ff930a0b61ae35b173b4b5.32992919724107662747 WBNB sent to 0xc5001f60db92afcc23177a6c6b440a4226cb58bf in tx 0xfa1ece5381b9e2b2b83cb10faefde7632ca411bb38dd6bafe1f1140b1360f6ae.