All incidents

TRUST/FCN Flash-Swap Reward Exploit

Share
Dec 01, 2023 11:19 UTCAttackLoss: 502,963.34 BSC-USD, 250.99 FCNPending manual check2 exploit txWindow: 57s
Estimated Impact
502,963.34 BSC-USD, 250.99 FCN
Label
Attack
Exploit Tx
2
Addresses
2
Attack Window
57s
Dec 01, 2023 11:19 UTC → Dec 01, 2023 11:20 UTC

Exploit Transactions

TX 1BSC
0xb650e9f4b9eb023ea65b55ca4d088323e3d5bda377880dedb149a7fd3fd5c15f
Dec 01, 2023 11:19 UTCExplorer
TX 2BSC
0xbeea4ff215b15870e22ed0e4d36ccd595974ffd55c3d75dad2230196cc379a52
Dec 01, 2023 11:20 UTCExplorer

Victim Addresses

0x431abb27dab05f4e7cdeaa18390fe39364197500BSC
0xacb496dd4a8b6b9d1b99d422b8700f6ef932bc10BSC

Loss Breakdown

502,963.34BSC-USD
250.99FCN

Similar Incidents

Root Cause Analysis

TRUST/FCN Flash-Swap Reward Exploit

1. Incident Overview TL;DR

On BNB Smart Chain, an unprivileged attacker cluster used two public transactions to first create reward-eligible positions and then exploit the public reward contract 0x431Abb27dAB05f4E7cDeAA18390fE39364197500. In tx 0xb650e9f4b9eb023ea65b55ca4d088323e3d5bda377880dedb149a7fd3fd5c15f, the attacker contract 0x791626eb05e60fac973646ac8d67b008b939fe88 bought a public position, bound into the referral tree, called reward selector 0x1f6b08a4, staked 200e18, deployed helper contract 0xfd8043814f72a500f01ddcbbb375a1d56bb1ee17, and repeated the same public priming flow for the helper. In tx 0xbeea4ff215b15870e22ed0e4d36ccd595974ffd55c3d75dad2230196cc379a52, the attacker flash-borrowed BSC-USD from the FCN/BSC-USD PancakePair 0xacb496dd4a8b6b9d1b99d422b8700f6ef932bc10, collapsed the pair BSC-USD balance to 0.02, claimed an inflated FCN reward inside the callback, repaid the pair with only 10,000 BSC-USD plus 100 FCN, and forwarded 503,468.345335579475662703 BSC-USD to the attacker EOA.

The root cause is a direct pricing error in the reward claim path. The reward contract converts a fixed USDT-denominated reward bucket into FCN by reading instantaneous token balances from a manipulable PancakePair inside the same transaction. Because those balances can be flash-manipulated, a same-transaction reserve collapse turns a fixed 10e18 reward bucket into an oversized 250.985538698669186971 FCN payout. This is an ACT incident: no privileged keys, governance rights, or private artifacts were required.

2. Key Background

The vulnerable system is the TRUST / FCN reward system centered on reward contract 0x431Abb27dAB05f4E7cDeAA18390fE39364197500. The contract is not verified on the explorer, but the local decompilation and the live traces show two relevant public entrypoints:

  • selector 0x1f6b08a4, used during reward-position priming;
  • Stack(uint256), used to stake 200e18;
  • selector 0xd9574d4c, used during the exploit-time reward claim.

The price source used by the reward logic is the FCN/BSC-USD pair 0xacb496dd4a8b6b9d1b99d422b8700f6ef932bc10. The updated auditor evidence records that this address is a verified PancakePair, so the flash-swap capability and callback surface are deterministic. The attacker-side contracts 0x791626... and 0xfd804... are not the bug. Their decompilation shows hardcoded tx.origin == 0xa9ed... gates, which identifies them as attacker orchestration contracts rather than protocol components.

The attacker first accumulated public inventory through earlier swaps and transfers, including txs 0xfc090b1dd85d57875d5c7b11ef2e3d131df355ee4444a2ae1dec7cefa708cba9, 0xd2f65c802e0ea6673b85026d9d0be8f429f64f52b4f6045b011065c5aa3f31b7, 0x3dbdc3804d4b176829a74a7726530bc4fdfaa0901838272821c21d6076dcfd0c, 0x8a6a05c19681d3c85d82426952858d5a8bf97ed8625235b4161f5a2b9e89e7c9, 0xcc653611297cded11e089e6d946a1635d89db44b137d9d8888dd3d9a8871c319, and 0xbda4b759099c6e3fc3aee6c60161e87b2f44e07d23824e36c24212b1e2db3956. Those public acquisitions mattered only because they funded the later public priming and claim calls.

3. Vulnerability Analysis & Root Cause Summary

This is an ATTACK-class protocol bug, not a benign arbitrage or a mere attacker-orchestration issue. The reward contract uses raw same-transaction pair balances as an oracle for converting a fixed BSC-USD reward bucket into FCN. The invariant that should hold is straightforward: a fixed USDT-denominated reward bucket must convert into FCN using a manipulation-resistant price, so the FCN payout cannot depend on transient same-transaction reserve distortions. Instead, the contract reads BEP20USDT.balanceOf(pair) and FCNToken.balanceOf(pair) during the claim callback and derives the FCN payout before reserves are restored.

The decompiled reward contract shows the pricing and claim paths reading token balances from the stored pair address:

function Unresolved_78023b1c() public payable returns (uint256) {
    address var_b = address(store_a);
    address(store_b).Unresolved_70a08231(var_b); // pair USDT balance
    address(store_c).Unresolved_70a08231(var_b); // pair FCN balance
    return var_k / var_c.length;
}

function Unresolved_d9574d4c() public payable {
    address var_d = address(store_a);
    address(store_b).Unresolved_70a08231(var_d); // pair USDT balance
    address(store_c).Unresolved_70a08231(var_d); // pair FCN balance
}

That design is exploitable because PancakePair balances are manipulable within a single flash-swap callback. The exploit trace proves the exact breakpoint: d9574d4c() runs while the pair is temporarily holding only 0.02 BSC-USD and 0.501971077397338362 FCN, so the reward conversion path pays far more FCN than a fair price would allow. The attacker then restores enough balances to satisfy PancakePair settlement while keeping the drained BSC-USD and most of the FCN overpayment.

4. Detailed Root Cause Analysis

The priming transaction shows the attacker using only public protocol surfaces to create claimable state. The trace for tx 0xb650... records the exact sequence:

0x90bf82c772f16651d6ae51D42c90c84aE703Eb42::buy(7690)
0x04c5bcFcae55591D72E01c548863F4E754C74339::bindParent(0x041285A02A7fabc448893f6c1766e4B592f46f96)
0x431Abb27dAB05f4E7cDeAA18390fE39364197500::1f6b08a4(...1)
0x431Abb27dAB05f4E7cDeAA18390fE39364197500::Stack(200000000000000000000)
CREATE -> 0xFd8043814f72a500F01ddCBbB375a1d56bB1ee17
0xFd8043814f72a500F01ddCBbB375a1d56bB1ee17::13c4f87c()
0x90bf82c772f16651d6ae51D42c90c84aE703Eb42::buy(6069)
0x04c5bcFcae55591D72E01c548863F4E754C74339::bindParent(0x791626EB05E60FAc973646ac8D67B008b939fE88)
0x431Abb27dAB05f4E7cDeAA18390fE39364197500::1f6b08a4(...1)
0x431Abb27dAB05f4E7cDeAA18390fE39364197500::Stack(200000000000000000000)

That priming step leaves the attacker cluster in a deterministic pre-exploit state. The tx 0xb650... balance diff shows the primary contract starting with 1180008559000000000000 BSC-USD before tx1 and ending tx1 with 505004279500000000000 BSC-USD, while the newly deployed helper finishes tx1 with 335004279500000000000 BSC-USD. The updated profit snapshot uses those observed balances, rather than any estimated mark-to-market figure, to define the ACT success predicate.

The exploit transaction then abuses the pricing breakpoint. The trace for tx 0xbeea4f... records the decisive sequence:

0x791626EB05E60FAc973646ac8D67B008b939fE88::claim(PancakePair, 20000000000000000, 10000000000000000000000, 100000000000000000000)
  PancakePair::swap(0, 512963341056079475662703, 0x791626..., data)
    0x791626...::pancakeCall(...)
      0x431Abb27dAB05f4E7cDeAA18390fE39364197500::d9574d4c()
        BEP20USDT::balanceOf(PancakePair) -> 20000000000000000
        FCNToken::balanceOf(PancakePair) -> 501971077397338362
        FCNToken::transfer(0x791626..., 225886984828802268274)
        FCNToken::transfer(0x19C4..., 25098553869866918697)
      BEP20USDT::transfer(PancakePair, 10000000000000000000000)
      FCNToken::transfer(PancakePair, 100000000000000000000)
      BEP20USDT::transfer(0xA9eDec..., 503468345335579475662703)

The same trace shows the reward bucket at storage slot 0x9c6375cd... changing from 0x8ac7230489e80000 (10e18) to 0, which is consistent with a fixed pending reward bucket being consumed at the manipulated price. The pricing math claimed in root_cause.json is consistent with the trace: 10e18 * 0.501971077397338362e18 / 0.02e18 yields the observed 250.985538698669186971 FCN total reward, split into 225.886984828802268274 FCN to the attacker contract and 25.098553869866918697 FCN to 0x19C4....

The balance diff for tx 0xbeea4f... measures the result:

{
  "pair_bsc_usd_delta": "-502963341056079475662703",
  "reward_fcn_delta": "-250985538698669186971",
  "attacker_eoa_bsc_usd_delta": "503468345335579475662703",
  "primary_fcn_delta": "125886984828802268274"
}

The pair ends with 10000020000000000000000 BSC-USD and 85501971077397338362 FCN, matching the incident-shaped post-settlement state. Because FCN transfer tax burns 15 FCN and only 85 FCN reaches the pair, the attacker can repay with 100 FCN while the pair’s final FCN balance still reflects only an 85 FCN increase.

The revised success predicate is also deterministic. The attacker cluster’s directly held BSC-USD balances are:

{
  "pre_state_cluster_total": "1180008559000000000000",
  "post_state_cluster_total": "503803349615079475662703",
  "delta_raw": "502623341056079475662703"
}

This conservative direct-BSC-USD delta excludes any valuation of the retained 125887953514529756405 FCN and ignores gas because gas was paid in BNB, not BSC-USD. It still proves a large positive ACT profit.

5. Adversary Flow Analysis

The attacker cluster is composed of EOA 0xa9edec4496bd013dac805fb221edefc53cbfaf05, primary contract 0x791626eb05e60fac973646ac8d67b008b939fe88, and helper contract 0xfd8043814f72a500f01ddcbbb375a1d56bb1ee17. The end-to-end flow is:

  1. Publicly acquire inventory through observable swaps and transfers.
  2. Use tx 0x741efdb50b789f236b810766b6b7acdd3c0f6e830ab8ac74b5059ca665b8e8c7 to initialize approvals.
  3. In tx 0xb650..., use buy(7690), bindParent, reward selector 0x1f6b08a4, and Stack(200e18) to create a primary reward position.
  4. Deploy helper 0xfd804..., transfer public inventory into it, call buy(6069), bind it to the primary contract as parent, and repeat the same reward-priming calls.
  5. In tx 0xbeea4f..., call the primary contract’s claim/orchestration path, which:
    • flash-borrows 512,963.341056079475662703 BSC-USD from the PancakePair,
    • enters pancakeCall,
    • triggers d9574d4c() while the pair BSC-USD balance is only 0.02,
    • receives the inflated FCN reward,
    • repays the pair with 10,000 BSC-USD plus 100 FCN,
    • forwards 503,468.345335579475662703 BSC-USD to the EOA.

The critical decision point is the flash-swap callback. Before that callback, the reward contract would price the fixed reward bucket using the real pair inventory. During the callback, it instead prices from manipulated reserves that the attacker controls for the remainder of the transaction.

6. Impact & Losses

The measurable impact is twofold:

  • the FCN/BSC-USD pair loses 502963341056079475662703 BSC-USD (502,963.341056079475662703);
  • the reward contract overdistributes 250985538698669186971 FCN (250.985538698669186971).

The attacker cluster also retains material value after settlement:

  • direct BSC-USD cluster gain: 502623341056079475662703 raw units;
  • direct EOA receipt in tx2: 503468345335579475662703 raw units;
  • retained FCN on the primary contract after pair repayment: 125886984828802268274 raw units;
  • additional FCN sent to address 0x19C4a6b4AbFe88161F07C4fA2229a4120ACFd7d5: 25098553869866918697 raw units.

The exploit required no privileged keys, no governance powers, and no private attacker artifact beyond fresh contract deployment. Any unprivileged actor able to observe the same public state and use the same pair flash-swap surface can realize the same opportunity while the reward contract continues to trust transient pair balances.

7. References

  • Seed priming transaction: 0xb650e9f4b9eb023ea65b55ca4d088323e3d5bda377880dedb149a7fd3fd5c15f
  • Seed exploit transaction: 0xbeea4ff215b15870e22ed0e4d36ccd595974ffd55c3d75dad2230196cc379a52
  • Prior approval/init transaction: 0x741efdb50b789f236b810766b6b7acdd3c0f6e830ab8ac74b5059ca665b8e8c7
  • Public inventory acquisition txs: 0xfc090b1dd85d57875d5c7b11ef2e3d131df355ee4444a2ae1dec7cefa708cba9, 0xd2f65c802e0ea6673b85026d9d0be8f429f64f52b4f6045b011065c5aa3f31b7, 0x3dbdc3804d4b176829a74a7726530bc4fdfaa0901838272821c21d6076dcfd0c, 0x8a6a05c19681d3c85d82426952858d5a8bf97ed8625235b4161f5a2b9e89e7c9, 0xcc653611297cded11e089e6d946a1635d89db44b137d9d8888dd3d9a8871c319, 0xbda4b759099c6e3fc3aee6c60161e87b2f44e07d23824e36c24212b1e2db3956
  • Reward contract: 0x431Abb27dAB05f4E7cDeAA18390fE39364197500
  • Pair contract: 0xACB496dd4A8b6B9D1B99D422b8700F6EF932Bc10
  • Attacker EOA: 0xa9edec4496bd013dac805fb221edefc53cbfaf05
  • Primary attacker contract: 0x791626eb05e60fac973646ac8d67b008b939fe88
  • Helper attacker contract: 0xfd8043814f72a500f01ddcbbb375a1d56bb1ee17
  • Verified pair evidence: BscScan source for 0xACB496dd4A8b6B9D1B99D422b8700F6EF932Bc10
  • Supporting evidence artifacts used for validation:
    • reward-contract decompilation;
    • attacker-contract decompilation;
    • tx traces and balance diffs for 0xb650... and 0xbeea4f...;
    • updated attacker-cluster BSC-USD balance snapshot;
    • updated pair verification artifact.