We do not have a reliable USD price for the recorded assets yet.
0xd081d6bb96326be5305a6c00dd51d1799971794941576554341738abc1ceb2020x971d08bba900230298add23e61e04b04226b5073BSCOn BNB Chain, transaction 0xd081d6bb96326be5305a6c00dd51d1799971794941576554341738abc1ceb202 drained reward tokens from redemption contract 0x971d08bba900230298add23e61e04b04226b5073. The attacker repeatedly called selector 0xfbe81135 with (tokenId=1, amount=0). Each call emitted an ERC1155 TransferSingle event with zero amount on 0x5eb47c41fc9becf123c9e484c51de37830842add, but the victim still transferred a fixed 285000000000000000000 units of Token (0x7fe5faf242015cf769ae7fea565b96351dd957a2) to the attacker helper.
The root cause is a broken redemption invariant: the victim pays a fixed ERC20 reward without enforcing a positive NFT amount and without validating that any ERC1155 inventory actually moved. Because the ERC1155 path also accepts zero-amount transfers, an unprivileged caller with standard operator approval can repeat the call until the victim treasury is depleted.
The victim contract is unverified, so the analysis relies on bytecode, disassembly, and the seed execution trace. Collector artifacts show the contract is not a proxy and exposes selector 0xfbe81135 as the redemption entrypoint. Storage-derived getters confirm the victim points to ERC1155 contract 0x5eb47c41fc9becf123c9e484c51de37830842add, reward token 0x7fe5faf242015cf769ae7fea565b96351dd957a2, owner 0x3eDb1eBCC67b27189E5881eb688D56F59b9B77d0, and fixed payout amount .
285000000000000000000The exploit does not depend on attacker-private artifacts. The on-chain trace shows the helper contract 0x3559ee265fc9c5c9a333b07e0199480b4a84f369 setting ERC1155 approval and then calling the public victim selector in a loop. Before those calls, balanceOf(attackerHelper, 1) returns zero. During each call, the victim queries ERC1155 balance, checks reward-token treasury balance, triggers safeTransferFrom(attackerHelper, victim, 1, 0), and then transfers the fixed ERC20 amount anyway.
This is an ATTACK-class logic flaw in a redemption workflow. The intended invariant is simple: the contract should only pay ERC20 rewards when the caller actually transfers a positive quantity of the required ERC1155 asset. The victim violates that invariant because reward amount is loaded from a fixed storage slot rather than derived from the requested NFT amount or a verified post-transfer delta. The function also does not reject amount == 0. That omission becomes exploitable because the paired ERC1155 contract accepts zero-amount transfers and emits a normal TransferSingle event without changing balances. The result is a redeem path that appears to succeed while moving no NFT inventory and still paying out real tokens. Repeating the call drains the treasury deterministically.
The victim dispatch table includes selector 0xfbe81135, matching the attack entrypoint:
Victim disassembly
00000049: PUSH4 0xfbe81135
0000004f: EQ
00000050: PUSH2 0x01fd
00000053: JUMPI
Inside that path, the victim checks its reward-token inventory via balanceOf(address(this)), then compares the result against storage slot 3, which is the fixed payout amount:
Victim disassembly
00000934: PUSH4 0x70a08231
...
00000997: PUSH1 0x03
00000999: SLOAD
0000099a: DUP2
0000099b: LT
0000099c: ISZERO
After that inventory check, the victim constructs a call to selector 0x0febdd49 on the ERC1155 contract using CALLER, ADDRESS, and the user-supplied arguments, then immediately prepares an ERC20 transfer using CALLER and SLOAD(3):
Victim disassembly
00000a12: PUSH4 0x0febdd49
00000a17: CALLER
00000a18: ADDRESS
...
00000a9f: PUSH4 0xa9059cbb
00000aa4: CALLER
00000aa5: PUSH1 0x03
00000aa7: SLOAD
The ERC1155 contract also exposes selector 0x0febdd49, confirming the victim is invoking a real token-transfer path rather than a mock:
ERC1155 disassembly
000001d7: PUSH4 0x0febdd49
000001dc: EQ
000001dd: PUSH2 0x025f
000001e0: JUMPI
The seed trace shows the exact exploit realization. For repeated calls to 0x971d08...::fbe81135(..., 0), the attacker helper's ERC1155 balance for token id 1 remains zero, the victim calls safeTransferFrom(..., 1, 0), the ERC1155 contract emits TransferSingle(..., 1, 0), and the victim still transfers 285000000000000000000 reward tokens to the helper:
Seed trace
0x971d08...::fbe81135(..., 0)
0x5eb47C...::balanceOf(0x3559ee..., 1) -> 0
Token::balanceOf(0x971d08...) -> 113730000000000000000000
0x5eb47C...::safeTransferFrom(0x3559ee..., 0x971d08..., 1, 0)
emit TransferSingle(..., 1, 0)
Token::transfer(0x3559ee..., 285000000000000000000)
emit Transfer(from: 0x971d08..., to: 0x3559ee..., value: 285000000000000000000)
The balance diff confirms the aggregate loss: victim 0x971d08... lost 285000000000000000000000 raw units of Token, while the attacker helper accumulated the drained inventory before liquidation. That is the broken invariant in measurable form.
The attacker flow is fully on-chain and permissionless once ordinary ERC1155 approval is set.
First, EOA 0x835b45d38cbdccf99e609436ff38e31ac05bc502 invokes helper contract 0x3559ee265fc9c5c9a333b07e0199480b4a84f369. The helper obtains or uses operator approval so the victim can invoke ERC1155 transfer logic against the helper. Second, the helper repeatedly calls victim selector 0xfbe81135 with (1, 0). Each iteration preserves helper NFT balance at zero but pays out another fixed 285e18 tokens. Third, after collecting 285000000000000000000000 raw units, the helper approves PancakeRouter and swaps the drained token inventory through pair 0xb726ebb38ed94239f5dd4f74a9da30ab803e4568 into WBNB.
The trace makes the loop explicit: it shows many consecutive fbe81135(..., 0) calls, each followed by zero-amount TransferSingle and fixed-size ERC20 transfer events. It then shows Token::balanceOf(0x3559ee...) -> 285000000000000000000000, followed by PancakeRouter::swapExactTokensForTokensSupportingFeeOnTransferTokens(285000000000000000000000, ...). The exploit therefore goes from setup, to repeated extraction, to liquidation in a single transaction.
The directly measured loss is the victim treasury depletion of Token:
[
{
"token_symbol": "Token",
"amount": "285000000000000000000000",
"decimal": 18
}
]
This is 285000 whole tokens at 18 decimals. The impact is broader than a one-off payout bug because the flaw is repeatable and permissionless. Any actor who can send the same public call sequence against a funded victim instance can realize the same state transition: no NFT inventory lost by the caller, but fixed ERC20 rewards transferred out of the victim.
0xd081d6bb96326be5305a6c00dd51d1799971794941576554341738abc1ceb2020x971d08bba900230298add23e61e04b04226b50730x5eb47c41fc9becf123c9e484c51de37830842add0x7fe5faf242015cf769ae7fea565b96351dd957a22850000000000000000000000xfbe81135, SLOAD(3), 0x0febdd49, and 0xa9059cbb0x0febdd49