OLY staking/router reward-abuse drains BEP20USDT from staking flows
Exploit Transactions
0x827e23d6dc6bfdc06d6062f53203fd1ca6f3cc00f8bad21ea6bf9aa7d9b349edVictim Addresses
0x77190f0c8e97514c4fd3895fb5b4fb464961b46fBSC0x46e185726084e8dc8a3ee8bd955e476237d49074BSC0x55d398326f99059ff775485246999027b3197955BSC0x544028231562a43b106fbceca722b65cb5c861b0BSCLoss Breakdown
Similar Incidents
DexToken BEP20USDT pool drain from token-logic exploit
39%BTNFT transferFrom reward-claim bypass drains vested BTTToken rewards
37%BSC staking pool reentrancy drain
36%BSC ORT Staking 1-to-6000 Reward Mint ACT Opportunity
35%Marketplace proxy 0x9b3e9b92 bug drains USDT and mints rewards
35%H2O helper-token reward drain from unauthorized claim loop
35%Root Cause Analysis
OLY staking/router reward-abuse drains BEP20USDT from staking flows
BNB Chain (chainid 56) protocol OLY’s router, deployed as implementation contract 0x77190F0C8e97514c4fd3895FB5B4fb464961b46F behind TransparentUpgradeableProxy 0x46e185726084e8Dc8a3eE8bd955e476237d49074, exposes a function Unresolved_6f73978a that allows any caller to specify an arbitrary BEP20 token owner address and invoke BEP20USDT.transferFrom(owner, proxy, amount) using pre-existing approvals to the proxy. An unprivileged adversary EOA 0xf10395d26262b92cc95729f274965868bd7f938b deployed a helper contract 0x85616b87D4D5313D4Cb1f91370AE5A2297b3a2AB and, in a single transaction 0x827e23d6dc6bfdc06d6062f53203fd1ca6f3cc00f8bad21ea6bf9aa7d9b349ed at block 74081238, iterated over many USDT holders who had previously approved the proxy, draining their BEP20USDT balances via this arbitrary-from transferFrom path and routing proceeds into adversary-controlled aggregation addresses. The adversary cluster’s BEP20USDT holdings increased by 179644.562028178677753413 USDT, with victims collectively losing the same amount.
Key Background
The protocol is an OLY staking/router system on BNB Chain that integrates BEP20USDT (0x55d398326f99059ff775485246999027b3197955) and OLY (0x544028231562a43b106fbceca722b65cb5c861b0). User flows rely on a TransparentUpgradeableProxy at 0x46e185726084e8Dc8a3eE8bd955e476237d49074, which delegates calls to router implementation 0x77190F0C8e97514c4fd3895FB5B4fb464961b46F. Many EOAs had granted standard BEP20USDT approvals to the proxy, enabling it to move their USDT in normal staking or swapping operations.
The ACT pre-state σ_B is BNB Chain state at block 74081237, immediately before the adversary seed transaction at block 74081238. It consists of:
- BEP20USDT balances and allowances for victim EOAs and the adversary-related cluster.
- OLY token balances used in swap and staking flows.
- Deployment and configuration of the proxy
0x46e18572…delegating to router implementation0x7719…b46F. - Established BEP20USDT approvals from many EOAs to the proxy.
This pre-state is evidenced by:
- Seed metadata for tx
0x827e23d6…:
// Seed metadata for 0x827e23d6… (BNB Chain, chainid 56)
{
"chainid": 56,
"txhash": "0x827e23d6dc6bfdc06d6062f53203fd1ca6f3cc00f8bad21ea6bf9aa7d9b349ed",
"etherscan": {
"tx": {
"result": {
"from": "0xf10395d26262b92cc95729f274965868bd7f938b",
"hash": "0x827e23d6dc6bfdc06d6062f53203fd1ca6f3cc00f8bad21ea6bf9aa7d9b349ed",
"to": null,
"value": "0x0"
}
}
}
}
(Source: seed metadata for tx 0x827e23d6…, artifacts under artifacts/root_cause/seed/56/0x827e23d6…/metadata.json.)
- BEP20USDT and OLY verified source code:
BEP20USDTat0x55d398326f99059ff775485246999027b3197955(Contract.solunderartifacts/root_cause/seed/56/0x55d3983…/src/).OLYat0x544028231562a43b106fbceca722b65cb5c861b0(OHM.solunderartifacts/root_cause/seed/56/0x5440282…/src/).
- Router implementation decompile and ABI:
artifacts/root_cause/data_collector/iter_1/contract/56/0x77190F0C8e97514c4fd3895FB5B4fb464961b46F/decompile/….
The ACT opportunity uses a single adversary-crafted transaction sequence b consisting of one contract-creation transaction on chainid 56:
- Transaction
b[1]:txhash:0x827e23d6dc6bfdc06d6062f53203fd1ca6f3cc00f8bad21ea6bf9aa7d9b349edfrom:0xf10395d26262b92cc95729f274965868bd7f938b- Type: standard BNB Chain contract-creation transaction with zero native value and sufficient gas.
- Feasibility: sendable by any unprivileged EOA via public RPC/mempool; the calldata deploys a helper contract that, in the same transaction, drives arbitrary-from
transferFromcalls through the established proxy/implementation.
No privileged roles, admin keys, or private orderflow are required to realize this strategy.
Vulnerability Analysis
The root cause is a design flaw in router implementation 0x7719…b46F behind TransparentUpgradeableProxy 0x46e18572…, specifically function selector 0x6f73978a (Unresolved_6f73978a in the decompile). This function accepts an owner address parameter and uses it directly as the from address in BEP20USDT.transferFrom, without constraining it to msg.sender or otherwise verifying ownership.
From the decompiled router code:
/// @custom:selector 0x6f73978a
/// @custom:signature Unresolved_6f73978a(uint256 arg0, uint256 arg1, address arg2, address arg3, address arg4) public payable
function Unresolved_6f73978a(uint256 arg0, uint256 arg1, address arg2, address arg3, address arg4) public payable {
// ...
address var_d = address(arg2); // token address
// ...
address var_e = address(arg3); // owner address
address var_g = address(this); // proxy / router context
uint256 var_h = arg0; // amount
// ...
(bool success, bytes memory ret0) = address(arg2).Unresolved_23b872dd(var_e); // call transferFrom
// ...
}
(Source: heimdall decompile for router implementation 0x7719…b46F, 0x7719…-decompiled.sol.)
This decompile, combined with the ABI and traces, shows that:
arg2is the BEP20 token address (BEP20USDT in the attack).arg3is the token-owner address used as thefromparameter intransferFrom.- The function allows any caller to choose
arg3arbitrarily.
The BEP20USDT token at 0x55d3983… implements standard ERC-20 semantics, with transferFrom(owner, spender, amount) checking allowance[owner][spender] and balanceOf(owner) before moving tokens. Many users had previously approved proxy 0x46e18572… to spend their USDT.
A benign pre-incident transaction shows intended usage of this path by a regular user:
TransparentUpgradeableProxy::fallback(
0x6f73978a...
... token = 0x55d398326f99059ff775485246999027b3197955 (BEP20USDT)
... owner = 0x939599136029208E46A1b79d485E12fec94c7056
... router/treasury = 0x13903A7E780ded720e2F35d5B8904d556a0552E0
)
├─ 0x7719…b46F::6f73978a(...) [delegatecall]
│ ├─ PancakeFactory::getPair(USDT, OLY)
│ ├─ BEP20USDT::transferFrom(
│ │ from: 0x939599136029208E46A1b79d485E12fec94c7056,
│ │ to: TransparentUpgradeableProxy: [0x46e18572…],
│ │ value: 60610300000000000000
│ ├─ BEP20USDT::approve(PancakeRouter: [0x10ED43C7…], 10307335639681778901944)
│ ├─ PancakeRouter::swapExactTokensForTokensSupportingFeeOnTransferTokens(...)
│ └─ OLY::transferFrom / Treasury flows
(Source: pre-incident user trace, artifacts/root_cause/data_collector/iter_4/tx/56/0xd6915f9e…/trace.cast.log.)
In this benign case, a user calls the router via the proxy, supplying their own address as the owner argument, and the router uses transferFrom(owner, proxy, amount) to pull USDT into the proxy and swap into OLY.
The vulnerability arises because Unresolved_6f73978a:
- Does not constrain
arg3(owner) to equalmsg.senderor any whitelisted account. - Relies solely on existing ERC-20 allowances from
ownerto the proxy and onowner’s balance. - Uses the proxy as the
spenderintransferFrom, so any pre-existingallowance[owner][proxy]is sufficient.
Therefore, any unprivileged caller who can call Unresolved_6f73978a via the proxy, and who knows a list of addresses with non-zero USDT balances and approvals to the proxy, can:
- Set
arg2 = BEP20USDT, - Set
arg3 = victim_address, - Set
arg4to the treasury/router address, and - Choose an amount up to the victim’s balance/allowance,
causing
BEP20USDT.transferFrom(victim, proxy, amount)to succeed, followed by swaps and OLY transfers, without any victim interaction at attack time.
Detailed Root Cause Analysis
The ACT opportunity is instantiated at block 74081238 via a single adversary-crafted transaction:
- Adversary transaction:
- Chain: BNB Chain (
chainid = 56) - Tx hash:
0x827e23d6dc6bfdc06d6062f53203fd1ca6f3cc00f8bad21ea6bf9aa7d9b349ed - From: EOA
0xf10395d26262b92cc95729f274965868bd7f938b - Type: contract-creation with zero native value
- Chain: BNB Chain (
Seed traces for this transaction show the following sequence:
[46711210] → new <unknown>@0x85616b87D4D5313D4Cb1f91370AE5A2297b3a2AB(...)
...
├─ TransparentUpgradeableProxy::fallback(0x6f73978a...)
│ ├─ 0x7719…b46F::6f73978a(..., token = BEP20USDT, owner = victim, ...)
│ │ ├─ BEP20USDT::transferFrom(victim, TransparentUpgradeableProxy: [0x46e18572…], amount)
│ │ ├─ BEP20USDT::approve(PancakeRouter: [0x10ED43C7…], ...)
│ │ ├─ PancakeRouter::swapExactTokensForTokensSupportingFeeOnTransferTokens(...)
│ │ └─ OLY/treasury flows
├─ (pattern repeats for many victim EOAs)
(Source: seed transaction trace, artifacts/root_cause/seed/56/0x827e23d6…/trace.cast.log and artifacts/root_cause/data_collector/iter_2/tx/56/0x827e23d6…/trace.cast.log.)
The helper contract 0x8561…2AB is created by the adversary EOA and immediately used within the same transaction to drive multiple Unresolved_6f73978a calls via the proxy. For each victim address with a pre-existing BEP20USDT approval to the proxy, the helper:
- Sets the token parameter to BEP20USDT.
- Sets the owner parameter to the victim address.
- Triggers
BEP20USDT.transferFrom(victim, proxy, amount)under the victim’s existing allowance and balance. - Causes the proxy to approve PancakeRouter and swap USDT into OLY.
- Routes OLY and/or USDT proceeds into adversary-controlled aggregation addresses.
The BEP20USDT balance diff for the seed transaction quantifies these flows. Example entries:
{
"erc20_balance_deltas": [
{
"token": "0x55d398326f99059ff775485246999027b3197955",
"holder": "0xa78493b667b72322f3b0595d159d6d885e3ecd87",
"before": "63829659024483467636128",
"after": "0",
"delta": "-63829659024483467636128",
"contract_name": "BEP20USDT"
},
{
"token": "0x55d398326f99059ff775485246999027b3197955",
"holder": "0xcaaf3c41a40103a23eeaa4bba468af3cf5b0e0d8",
"before": "43124190617983759518989497",
"after": "43131693242983759518989498",
"delta": "7502625000000000000001",
"contract_name": "BEP20USDT"
}
]
}
(Source: seed balance diff, artifacts/root_cause/seed/56/0x827e23d6…/balance_diff.json.)
These entries are representative:
- Victim EOAs such as
0xA78493b667B72322F3b0595d159D6d885e3ecd87lose essentially all of their USDT in the seed transaction. - Adversary aggregation addresses such as
0xcaaf3c41a40103a23eeaa4bba468af3cf5b0e0d8show large positive USDT deltas.
The adversary cluster’s net BEP20USDT profit is computed by summing BEP20USDT before/after balances across:
- EOA
0xf10395d2…(attacker EOA). - Four aggregation addresses:
0xfd36427acaf5865f1683dd6fca8a5b8d83661ff90x60a558581e9875f1b3402bc45526cf71c03662070xe1cd1288683cd8496236343faea21fa22da5e20d0xcaaf3c41a40103a23eeaa4bba468af3cf5b0e0d8
From balance_diff.json:
- Cluster BEP20USDT before:
43405848.105313391278059015USDT. - Cluster BEP20USDT after:
43585492.667341569955812428USDT. - Net delta:
179644.562028178677753413USDT.
Native BNB gas for the seed transaction is measured separately:
- EOA
0xf10395d2…loses exactly0.003748100774962014BNB innative_balance_deltas. - Gas is not converted to USDT; the reference asset here is USDT only.
The ACT success predicate is therefore:
- Reference asset: USDT (BEP20USDT on BNB Chain).
- Adversary address cluster:
{0xf10395d2…, 0xfd3642…, 0x60a558…, 0xe1cd12…, 0xcaaf3c…}. - Success condition:
value_delta_in_reference_asset > 0for the cluster, which holds with+179644.562028178677753413USDT.
Adversary Flow Analysis
The adversary flow proceeds in two main stages.
1. Normal user flow via Unresolved_6f73978a (baseline)
The pre-incident transaction 0xd6915f9eb544d1a92cf3ec935250225869b72b787aa42064897c40f5e6555d3a shows a benign user interacting with the router:
- Caller: a regular EOA with USDT balance and an approval to the proxy.
- Call path:
TransparentUpgradeableProxy::fallback(0x6f73978a...)0x7719…b46F::6f73978a(...)viadelegatecallBEP20USDT.transferFrom(user, proxy, amount)BEP20USDT.approve(PancakeRouter, amount')PancakeRouter.swapExactTokensForTokensSupportingFeeOnTransferTokens(USDT → OLY)- OLY flows through treasury and staking contracts.
This trace confirms that:
- Users are expected to approve the proxy to spend their USDT.
Unresolved_6f73978areads the owner from calldata and uses it as thefromintransferFrom.- The function is part of normal router usage and not a hidden backdoor.
2. Adversary helper deployment and batched USDT draining
In the seed transaction 0x827e23d6…, the adversary EOA:
- Deploys helper contract
0x85616b87D4D5313D4Cb1f91370AE5A2297b3a2ABvia contract-creation. - Uses the helper, within the same transaction, to:
- Call
TransparentUpgradeableProxy::fallback(0x6f73978a...)repeatedly. - For each call, set:
token = BEP20USDT (0x55d3983…)owner = victim_EOA- Router/treasury address parameters to OLY treasury components.
- Trigger
BEP20USDT.transferFrom(victim, proxy, amount)using existingallowance[victim][proxy]andbalanceOf(victim). - Approve PancakeRouter
0x10ED43C718714eb63d5aA57B78B54704E256024Eto spend USDT from the proxy. - Swap drained USDT into OLY on PancakePair
0x6865704FF097b1105Ed42B8517020e14Fe9A2ABD. - Route OLY and potentially USDT proceeds into aggregation addresses.
- Call
The seed trace logs show many repetitions of this pattern, each time with a different victim EOA. The balance diff confirms that:
- Victims lose their USDT in a single block and end with zero or near-zero balances.
- The adversary cluster receives all of the net positive USDT.
Post-incident txlists for the four large aggregation addresses in artifacts/root_cause/data_collector/iter_4/address/56/ are empty JSON arrays across windows 74500000–76000000 (or 74150000–76000000), indicating that within the collected range, there are no outbound transactions from these addresses. The stolen USDT remains concentrated at these addresses in the observed blocks.
Impact & Losses
The total quantified loss in BEP20USDT is:
179644.562028178677753413USDT
This amount is computed directly from BEP20USDT balance deltas in balance_diff.json for:
- The adversary-related cluster
{0xf10395d2…, 0xfd3642…, 0x60a558…, 0xe1cd12…, 0xcaaf3c…}. - The victim EOAs drained via the helper’s repeated
Unresolved_6f73978acalls.
Key impact points:
- Dozens of BEP20USDT holders who had approved proxy
0x46e18572…see large negative BEP20USDT deltas and post-tx balances of zero inbalance_diff.json. - The adversary cluster’s combined BEP20USDT holdings increase by
179644.562028178677753413USDT. - The adversary EOA
0xf10395d2…pays approximately0.003748100774962014BNB in gas, recorded innative_balance_deltas. - Within the post-incident txlist windows for the four aggregation addresses, there are no outgoing transactions; the stolen USDT remains in those addresses in the observed data.
The loss figure is entirely on-chain and does not depend on off-chain pricing oracles; values are computed in unit terms of BEP20USDT (18 decimals) from balance diffs.
References
- [1] Seed transaction metadata and BEP20USDT/OLY balance diffs for
0x827e23d6…:artifacts/root_cause/seed/56/0x827e23d6dc6bfdc06d6062f53203fd1ca6f3cc00f8bad21ea6bf9aa7d9b349ed/
- [2] Router implementation decompile and ABI (implementation
0x77190F0C8e97514c4fd3895FB5B4fb464961b46Fbehind proxy0x46e18572…):artifacts/root_cause/data_collector/iter_1/contract/56/0x77190F0C8e97514c4fd3895FB5B4fb464961b46F/decompile/
- [3] Pre-incident user transaction trace invoking
Unresolved_6f73978avia the proxy:artifacts/root_cause/data_collector/iter_4/tx/56/0xd6915f9eb544d1a92cf3ec935250225869b72b787aa42064897c40f5e6555d3a/trace.cast.log
- [4] Post-incident txlists for large BEP20USDT aggregation addresses:
artifacts/root_cause/data_collector/iter_4/address/56/
These references are all derived from canonical on-chain data (RPC queries, logs, traces) and publicly available contract metadata, and collectively support the ACT opportunity characterization and the protocol-level root cause.