52634 sc high batch yield distribution has a mathematical flaw that enables economic manipulation
Submitted on Aug 12th 2025 at 07:39:34 UTC by @spongebob for Attackathon | Plume Network
Report ID: #52634
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
The distributeYieldWithLimit function in ArcToken contains a mathematical flaw that allows attackers to steal disproportionate shares of yield distributions.
https://github.com/immunefi-team/attackathon-plume-network/blob/580cc6d61b08a728bd98f11b9a2140b84f41c802/arc/src/ArcToken.sol#L466-L555
The issue stems from the function's design where each call recalculates effectiveTotalSupply dynamically but continues using the original totalAmount for share calculations.
https://github.com/immunefi-team/attackathon-plume-network/blob/580cc6d61b08a728bd98f11b9a2140b84f41c802/arc/src/ArcToken.sol#L540
This creates a mathematical inconsistency: effectiveTotalSupply is recalculated for each batch by iterating through all current holders and checking their eligibility,
https://github.com/immunefi-team/attackathon-plume-network/blob/580cc6d61b08a728bd98f11b9a2140b84f41c802/arc/src/ArcToken.sol#L510-L516
while totalAmount remains the original campaign amount across all batches and never accounts for previously distributed amounts.
Also, the contract stores no campaign-level state between batches to track distributed amounts or snapshot initial conditions.
https://github.com/immunefi-team/attackathon-plume-network/blob/580cc6d61b08a728bd98f11b9a2140b84f41c802/arc/src/ArcToken.sol#L49-L60
An attacker can manipulate the holder set or eligibility status between batches by:
Transferring tokens to/from restricted addresses to change the
effectiveTotalSupplyManipulating their position in the holders enumerable set to ensure early batch processing
Coordinating with others to change yield eligibility status between batches
Example scenario demonstrating the inconsistency:
Initial state: A=50, B=30, C=20 tokens;
totalAmount=100;effectiveTotalSupply=100Batch 1 (A): share = (100×50)/100 = 50 tokens distributed
Between batches: 10 tokens moved from B to restricted address
New state: A=50, B=20, C=20;
effectiveTotalSupply=40Batch 2 (B): share = (100×20)/40 = 50 tokens distributed (total paid: 100)
Batch 3 (C): share = (100×20)/40 = 50 tokens needed, but 0 remaining → revert
The yield token transfer only occurs on the first batch (startIndex == 0), but subsequent batches continue distributing from the same pool using the flawed calculation.
https://github.com/immunefi-team/attackathon-plume-network/blob/580cc6d61b08a728bd98f11b9a2140b84f41c802/arc/src/ArcToken.sol#L526-L528
Impact Details
Attackers can capture disproportionate shares of yield distributions that rightfully belong to other token holders. Later batches may revert due to insufficient contract balance, preventing legitimate holders from receiving their entitled yield.
Proof of Concept
Step 1: First Batch Distribution
Attacker calls
distributeYieldWithLimit(100, 0, 1)Function calculates
effectiveTotalSupply = 100(all holders eligible)Alice (first holder) gets:
(100 * 50) / 100 = 50yield tokensThe full 100 yield tokens are transferred to contract on
startIndex == 0Alice receives 50 yield tokens, contract has 50 remaining
Step 3: Second Batch Distribution
Attacker calls
distributeYieldWithLimit(100, 1, 1)for BobFunction recalculates
effectiveTotalSupply = 90Bob gets:
(100 * 20) / 90 = 22.22(rounded down to 22) yield tokensContract now has 28 yield tokens remaining
Bob received proportionally more than he should relative to the original distribution
Step 4: Third Batch Distribution
Attacker calls
distributeYieldWithLimit(100, 2, 1)for CharlieFunction still uses
totalAmount = 100and recalculatedeffectiveTotalSupply = 90Charlie should get:
(100 * 20) / 90 = 22.22yield tokensContract only has 28 tokens left; depending on rounding and previous transfers, Charlie may be underpaid or the transaction may revert
Total distributed exceeds what should have been fairly allocated, or later batches fail
Result
Alice got 50 tokens (should have been ~55.6 based on final supply if snapshots were used)
Bob got 22 tokens (timing-dependent)
Charlie gets 22 tokens or less (may be underpaid)
Total distributed does not preserve proportionality; eligible holders can be economically manipulated
References
Vulnerable code region: https://github.com/immunefi-team/attackathon-plume-network/blob/580cc6d61b08a728bd98f11b9a2140b84f41c802/arc/src/ArcToken.sol#L466-L555
(End of report)
Was this helpful?