All incidents

MaraToken mispriced sale drains WBNB from liquidity pool

Share
Sep 24, 2024 16:42 UTCAttackLoss: 19.8 WBNBManually checked1 exploit txWindow: Atomic

Root Cause Analysis

MaraToken mispriced sale drains WBNB from liquidity pool

1. Incident Overview TL;DR

On BSC (chainid 56) at block 42538916, an adversary EOA 0x3026c464d3bd6ef0ced0d49e80f171b58176ce32 used an orchestrator contract 0x1c4684B838CF4344C152BA18650D1524AF4f0F12 to take a DODO-style flash loan of 11 WBNB, unwrap it to 11 BNB, and pay it into a Mara token sale proxy 0xc6A8C02dD5A3DD1616EC072BFC7c9D3df9682A63. The Mara sale logic (MaraToken at 0xA3F6af29001874ed06C1BF41427e33256b1D97D4) minted a total of 3.168e22 Mara, of which 2.64e22 Mara were minted to the orchestrator and 5.28e21 Mara were minted directly into the Mara–WBNB PancakeSwap pair 0x6e82575ffa729471b9b412d689ec692225b1ffcb.

The newly minted Mara sitting in the PancakePair were immediately used as swap input: the orchestrator called PancakePair::swap to swap 5.28e21 Mara for 19.8 WBNB, repaid the 11 WBNB flash loan, and transferred the remaining 8.8 WBNB profit to the EOA, all within the same transaction 0x0fe3716431f8c2e43217c3ca6d25eed87e14d0fbfa9c9ee8ce4cef2e5ec4583c. Balance diffs and the trace show that gas cost for the EOA was 0.000961581 BNB, so the adversary’s net profit is 8.799038419 WBNB-equivalent while the Mara–WBNB pool loses 19.8 WBNB of liquidity.

The root cause is an issuer-side pricing and issuance design flaw in MaraToken::releaseTokenFromEventOfProject: the sale mints Mara into both the attacker and the AMM at a rate completely inconsistent with the AMM price and allows direct minting into the AMM reserves, enabling a deterministic, permissionless arbitrage that drains WBNB from the pool while preserving the AMM invariant.

2. Key Background

The Mara token ecosystem on BSC combines a primary issuance mechanism (a token sale) with secondary trading on a PancakeSwap-style constant-product AMM. The key on-chain components involved in this incident are:

  • MaraToken logic contract 0xA3F6af29001874ed06C1BF41427e33256b1D97D4, which implements the sale logic including releaseTokenFromEventOfProject.
  • Sale proxy 0xc6A8C02dD5A3DD1616EC072BFC7c9D3df9682A63, which forwards sale calls (such as selector 0x5fc985ea) to the MaraToken logic via delegatecall.
  • Mara–WBNB PancakeSwap V2 pair 0x6e82575ffa729471b9b412d689ec692225b1ffcb, whose verified source matches a standard PancakePair with constant-product invariant and 0.25% fee.
  • DODO-style flash-loan pool 0x6098A5638d8D7e9Ed2f952d35B2b67c34EC6B476, which provides a flashLoan function that can be called by arbitrary contracts.

In normal operation, primary issuance should either (a) respect the current AMM price when minting tokens that can be immediately sold into the pool, or (b) isolate primary issuance from AMM liquidity to avoid free arbitrage. Here, the sale contract mints Mara both to the attacker and directly into the AMM reserves using a fixed issuer-controlled rate (rateOneBnbToToken and related parameters) that is not tied to the AMM price, creating a structural price inconsistency.

The adversary model is a standard unprivileged searcher/attacker: a public EOA funds and triggers an orchestrator contract, which in turn interacts only with public methods on the DODO pool, the Mara sale proxy, the MaraToken logic (via delegatecall), and the PancakePair. No privileged roles or access-controlled helper contracts are required.

3. Vulnerability Analysis & Root Cause Summary

The vulnerability is an issuer-side mispricing and unsafe issuance design in Mara’s sale logic:

  • MaraToken::releaseTokenFromEventOfProject mints Mara according to issuer-configurable parameters (e.g. rateOneBnbToToken, percentRefToken, percentRefBnb, minBnb) without enforcing any relationship to the live Mara–WBNB AMM price.
  • The function is allowed to mint tokens directly into the Mara–WBNB PancakePair contract, effectively increasing reserves in the AMM without any corresponding WBNB inflow.
  • In the exploited configuration, an 11 BNB payment results in 3.168e22 Mara being minted, of which 5.28e21 Mara are minted into the AMM, drastically changing the reserve ratio.

Because PancakePair accounting treats direct mints to the pair as additional token reserves, the 5.28e21 Mara credited to the pair are then consumed as amount0In in the next swap call. With pre-swap reserves of approximately 7.108e21 Mara and 4.6585877441571944643e19 WBNB, injecting 5.28e21 additional Mara and swapping out 19.8 WBNB still satisfies the constant-product invariant. This allows the attacker to extract 19.8 WBNB from the pool after paying only 11 BNB into the sale, leaving the sale contract with 11 BNB and the pool with inflated Mara supply and reduced WBNB reserves.

Hence, the root cause is a deterministically exploitable mismatch between primary issuance pricing and AMM pricing, combined with the ability to mint directly into AMM reserves, rather than any bug in the AMM or flash-loan logic.

4. Detailed Root Cause Analysis

This section walks through the technical mechanics from sale configuration to exploit.

4.1 Sale Logic and Mispricing

Decompiled MaraToken logic at 0xA3F6af29001874ed06C1BF41427e33256b1D97D4 shows variables such as rateOneBnbToToken, percentRefToken, percentRefBnb, and minBnb, as well as owner-controlled setter functions. The number of Mara tokens minted per unit of BNB in releaseTokenFromEventOfProject is determined purely by these on-chain parameters, not by querying or respecting the Mara–WBNB AMM price.

From the analyzer’s reconstruction and the Foundry trace, an 11 BNB payment via the sale proxy results in the following token mints:

  • 2.64e22 Mara to the orchestrator contract 0x1c46….
  • 2.64e21 Mara twice to the Mara–WBNB pair 0x6e82… (total 5.28e21 Mara minted into the AMM).

This results in an effective issuance rate that is far more favorable than the AMM-implied price, setting up a deterministic arbitrage opportunity for any actor who can fund the sale call and immediately sell the minted tokens into the pool.

4.2 PancakePair Reserve Dynamics

Verified source for 0x6e82575ffa729471b9b412d689ec692225b1ffcb matches a standard PancakeSwap V2 pair. Before the exploit, reconstructed reserves from Swap/Sync events in the trace are:

  • reserve0 ≈ 7.108468712344127575371e21 Mara
  • reserve1 ≈ 4.6585877441571944643e19 WBNB

This implies a pre-swap price of roughly 152.59 Mara per WBNB. After 5.28e21 Mara are minted directly into the pair and 5.28e21 Mara are used as amount0In in the subsequent swap, the reserves become:

  • reserve0 ≈ 1.2388468712344127575371e22 Mara
  • reserve1 ≈ 2.6785877441571944643e19 WBNB

The pair pays out exactly 19.8 WBNB (19800000000000000000 wei) to 0x1c46… while preserving the constant-product invariant given the new, inflated Mara reserves. The AMM is behaving as designed; the abnormal behavior comes from the sale logic injecting a large amount of Mara into the pool for insufficient BNB.

4.3 Invariant and Breakpoint

An explicit invariant for safe primary issuance in this system can be stated as:

The effective price at which Mara is minted into circulation (especially into AMM-accessible addresses) must not be significantly more favorable than the price implied by the live Mara–WBNB AMM, in order to prevent risk-free arbitrage that drains WBNB liquidity.

The concrete breakpoint operation that violates this invariant is:

// Simplified, conceptual form
function releaseTokenFromEventOfProject(uint256 bnbAmount, address buyer, address pair) external {
    // price determined by rateOneBnbToToken and related config, not AMM price
    uint256 totalMara = bnbAmount * rateOneBnbToToken;
    uint256 maraToBuyer = ...;   // e.g., 2.64e22 for 11 BNB
    uint256 maraToPair  = ...;   // e.g., 5.28e21 for 11 BNB
    _mint(buyer, maraToBuyer);
    _mint(pair, maraToPair);     // directly increases AMM reserves
}

At the exploited configuration, bnbAmount = 11 BNB leads to totalMara = 3.168e22, with maraToPair = 5.28e21. This direct mint into the pair at a mispriced rate is the critical breakpoint that creates the ACT opportunity.

5. Adversary Flow Analysis

This section reconstructs the attacker’s execution flow for transaction 0x0fe3716431f8c2e43217c3ca6d25eed87e14d0fbfa9c9ee8ce4cef2e5ec4583c on BSC (block 42538916), using the Foundry trace and balance diffs.

5.1 Setup and Flash Loan

  1. EOA 0x3026… sends a transaction to orchestrator contract 0x1c46… with selector 0xf8c0610b and arguments specifying:
    • Flash-loan pool: 0x6098A5638d8D7e9Ed2f952d35B2b67c34EC6B476
    • Loan amount: 11000000000000000000 (11 WBNB)
    • Loan token: WBNB 0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c
    • Sale proxy: 0xc6A8C02dD5A3DD1616EC072BFC7c9D3df9682A63
    • Target amount parameter: 0x112c7bb1858bc0000
  2. The orchestrator calls flashLoan on the DODO-style pool 0x6098…, which transfers 11 WBNB to 0x1c46… and invokes a callback (DPPFlashLoanCall) on the orchestrator.
  3. Inside the callback, 0x1c46… calls WBNB::withdraw(11000000000000000000), unwrapping 11 WBNB into 11 BNB, which are credited as native BNB to 0x1c46….

5.2 Mara Sale and Token Minting

  1. With exactly 11 BNB on hand, 0x1c46… calls the sale proxy 0xc6A8…::5fc985ea with msg.value = 11000000000000000000 (11 BNB) and calldata that encodes the Mara–WBNB pair address 0x6e82… (twice) and other parameters.
  2. The sale proxy 0xc6A8… delegates to MaraToken logic 0xA3F6… via delegatecall. Inside this delegatecall, MaraToken::releaseTokenFromEventOfProject is invoked three times:
    • Two calls mint 2640000000000000000000 Mara each directly to the PancakePair 0x6e82…, for a total of 5280000000000000000000 (5.28e21) Mara minted into the pair.
    • One call mints 26400000000000000000000 (2.64e22) Mara to the orchestrator contract 0x1c46….

These mints are fully visible in the trace and decompiler artifacts referenced in the analyzer’s what_we_know and in root_cause.json.

5.3 Swap and Profit Realization

  1. Immediately after the mints, 0x1c46… calls the Mara–WBNB pair:
PancakePair(0x6e82...).swap(
    0,
    19800000000000000000, // 19.8 WBNB out
    0x1c46...,            // recipient
    ""
);
  • The pair uses the newly minted 5.28e21 Mara in its reserves as amount0In.
  • The Swap and Sync logs show amount0In = 5280000000000000000000 and amount1Out = 19800000000000000000, with post-swap reserves consistent with constant-product accounting.
  1. After receiving 19.8 WBNB, the orchestrator:
    • Transfers 11 WBNB back to the DODO pool 0x6098… to repay the flash loan principal.
    • Transfers 8.8 WBNB to the EOA 0x3026…, leaving 0x1c46… with zero WBNB. This is confirmed by WBNB balanceOf calls and the ERC20 transfer events in the trace.

5.4 Profit and Gas Accounting

Native balance diffs for the transaction are as follows:

{
  "native_balance_deltas": [
    {
      "address": "0x3026c464d3bd6ef0ced0d49e80f171b58176ce32",
      "before_wei": "7691744964737646",
      "after_wei": "6730163964737646",
      "delta_wei": "-961581000000000"
    },
    {
      "address": "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c",
      "before_wei": "1277779004275425734166726",
      "after_wei": "1277768004275425734166726",
      "delta_wei": "-11000000000000000000"
    },
    {
      "address": "0xc6a8c02dd5a3dd1616ec072bfc7c9d3df9682a63",
      "before_wei": "16625794119000000000",
      "after_wei": "27625794119000000000",
      "delta_wei": "11000000000000000000"
    }
  ]
}

Interpreting these together with the ERC20 WBNB transfers:

  • The EOA pays 961581000000000 wei (0.000961581 BNB) in gas.
  • The sale proxy 0xc6A8… receives 11 BNB and retains it.
  • The orchestrator 0x1c46… receives 19.8 WBNB, repays 11 WBNB to the DODO pool, and transfers 8.8 WBNB to the EOA.

Treating BNB and WBNB as 1:1 convertible within this transaction, and ignoring any residual Mara holdings (conservative assumption), the adversary-related cluster’s net profit is:

  • Gross profit: 8.8 WBNB
  • Gas cost: 0.000961581 WBNB-equivalent
  • Net profit: 8.799038419 WBNB-equivalent

This matches the success predicate in root_cause.json and satisfies the ACT profit condition of strictly increasing net portfolio value in the reference asset after fees.

6. Impact & Losses

The immediate on-chain impact of the exploit is:

  • The Mara–WBNB PancakeSwap pool loses 19.8 WBNB of liquidity, while its Mara reserves increase by 5.28e21 tokens minted at a mispriced rate.
  • The Mara sale proxy 0xc6A8… receives and retains 11 BNB from the attacker-funded sale call.
  • The adversary-related cluster (EOA 0x3026… and orchestrator 0x1c46…) realizes a net profit of 8.799038419 WBNB-equivalent in a single transaction after gas.

From the protocol’s perspective, this is a classic primary-issuance-plus-AMM drain: the issuer’s mispriced minting and direct injection into the AMM allow an attacker to siphon WBNB from the liquidity pool without bearing corresponding economic risk. While the long-term impact on Mara token holders depends on downstream price dynamics and further transactions, the single-tx, anyone-can-take opportunity is clearly quantified by the 19.8 WBNB pool loss and 8.8 WBNB profit to the attacker.

7. References

Key on-chain identifiers and artifacts used to validate this root cause:

  • Chain: BNB Smart Chain (BSC), chainid = 56
  • Exploit transaction: 0x0fe3716431f8c2e43217c3ca6d25eed87e14d0fbfa9c9ee8ce4cef2e5ec4583c (block 42538916)
  • Adversary-related accounts:
    • EOA (attacker): 0x3026c464d3bd6ef0ced0d49e80f171b58176ce32
    • Orchestrator contract: 0x1c4684B838CF4344C152BA18650D1524AF4f0F12
  • Victim / stakeholder contracts:
    • Mara sale proxy: 0xc6A8C02dD5A3DD1616EC072BFC7c9D3df9682A63
    • MaraToken logic: 0xA3F6af29001874ed06C1BF41427e33256b1D97D4
    • Mara–WBNB PancakePair: 0x6e82575ffa729471b9b412d689ec692225b1ffcb
    • DODO-style flash-loan pool: 0x6098A5638d8D7e9Ed2f952d35B2b67c34EC6B476
    • WBNB token: 0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c

Primary evidence files (under artifacts/root_cause):

  • Seed index and balance diffs:
    • seed/index.json
    • seed/56/0x0fe3...4583c/balance_diff.json
  • Transaction metadata and receipt:
    • data_collector/iter_1/tx/56/0x0fe3...4583c/metadata.json
    • data_collector/iter_1/tx/56/0x0fe3...4583c/receipt.json
  • Full Foundry trace:
    • data_collector/iter_2/tx/56/0x0fe3...4583c/trace.cast.log
  • Contract source and decompilation:
    • PancakePair 0x6e82…: data_collector/iter_2/contract/56/0x6e82.../source/sourcecode.txt
    • MaraToken 0xA3F6…: data_collector/iter_1/contract/56/0xA3F6.../decompile/0xA3F6...-decompiled.sol
    • Orchestrator and DODO pool decompiles and ABI files under data_collector/iter_1/contract/56/...

These artifacts, together with the structured root_cause.json and analyzer iteration results, are sufficient for an independent reviewer to reproduce all key balances, reserve transitions, and call flows described in this report.