49787 sc high batched yield distribution doesn t account for transfers purchases between batches

Submitted on Jul 19th 2025 at 13:31:56 UTC by @Vanshika for Attackathon | Plume Networkarrow-up-right

  • Report ID: #49787

  • Report Type: Smart Contract

  • Report severity: High

  • Target: https://github.com/immunefi-team/attackathon-plume-network/blob/main/arc/src/ArcToken.sol

  • Impacts:

    • Theft of unclaimed yield

Description

Brief / Intro

ArcToken distributes yield in batches when the number of token holders is too high to fit in a single transaction. Any change in user balances occurring between separate batches can cause incorrect accounting or transaction reverts, potentially leading to loss or theft of yield.

Vulnerability Details

ArcToken::distributeYieldWithLimit() distributes yield across a range of token holders per call. holders is an enumerable set of addresses among whom the totalAmount is distributed. When distributing in batches:

  • The contract receives the totalAmount to distribute only on the first batch (when startIndex == 0).

  • Each batch recalculates the effectiveTotalSupply as the sum of ArcToken balances for eligible yield recipients for that batch.

  • Because effectiveTotalSupply is recalculated per batch, it can change between batches if balances are modified (transfers, purchases, sells).

  • A user who increases their balance immediately before an early batch receives a disproportionate share of that batch. They can then sell tokens so later batches find less yield remaining and may revert or leave holders unpaid.

Yield for a holder is calculated as:

Since effectiveTotalSupply can vary between batches, this leads to incorrect share allocations and potential reverts (or theft of yield).

Impact Details

  • High likelihood of accidental accounting errors and transaction reverts during normal use.

  • Malicious actors can exploit timing between batches to inflate yield for early batches and cause DoS or theft for later batches.

Proof of Concept

chevron-rightPoC test (click to expand)hashtag

Copy the following test into ArcToken.t.sol and run with:

forge test --mt test_batchDistribution --via-ir

Expected Result if maxHolders in batch2 = 1:

Expected result if you test with maxHolders = 2 or 3 for batch2: (uncomment david's assert statement)

Reproduction / Steps

1

Setup

  • Transfer tokens to multiple holders (alice, bob, charlie, david, ethan).

  • Blacklist owner from yield calculation (so owner balance is excluded from effectiveTotalSupply).

  • Approve yieldToken allowance for the contract.

  • Call distributeYieldWithLimit(YIELD_AMOUNT, 0, 3) to distribute the first batch.

2

Sandwich / Exploit

  • Before running subsequent batch calls, an attacker increases their ArcToken balance (e.g., charlie receives more tokens).

  • The attacker gets a larger share of the yield calculated in a prior or current batch due to increased holderBalance and a recalculated (smaller or larger) effectiveTotalSupply.

  • The attacker then sells tokens, reducing the remaining supply and causing later batches to find insufficient yield (leading to incorrect payments or reverts).

3

Result

  • Early batches overpay the attacker.

  • Later batches run out of funds or revert, causing yield loss or failed distributions for other holders.

Notes

  • The core issue is reliance on a per-batch recalculation of effectiveTotalSupply while the total distributed amount is provided only once at the start. Ensuring a fixed denominator across all batches (or transferring funds for each batch separately) is necessary to prevent this class of issue.

Was this helpful?