51146 sc low getmaxnumberoftokens returns wrong max number of tokens available to buy
Submitted on Jul 31st 2025 at 15:10:10 UTC by @Oxgritty for Attackathon | Plume Network
- Report ID: #51146
- Report Type: Smart Contract
- Report severity: Low
- Target: https://github.com/immunefi-team/attackathon-plume-network/blob/main/arc/src/ArcTokenPurchase.sol
Description
Brief / Intro
getMaxNumberOfTokensis used to know the quantity of tokens available to buy.- It returns a wrong amount because
totalAmountForSaleis not updated whenwithdrawUnsoldArcTokensis used to withdraw unsold ARC tokens.
Vulnerability Details
getMaxNumberOfTokensrelies oninfo.totalAmountForSaleto compute the available balance.withdrawUnsoldArcTokenswithdraws ARC tokens but does not updateinfo.totalAmountForSale.- As a result,
getMaxNumberOfTokenscan return an amount greater than the actual token balance held by the contract.
Impact Details
- A buyer calling
getMaxNumberOfTokensmay see an inflated available amount. - If the buyer attempts to purchase that inflated amount via
buy, thebuycall will revert due toContractBalanceInsufficient.
References
getMaxNumberOfTokensfunction:
https://github.com/immunefi-team/attackathon-plume-network/blob/580cc6d61b08a728bd98f11b9a2140b84f41c802/arc/src/ArcTokenPurchase.sol#L359withdrawUnsoldArcTokensfunction:
https://github.com/immunefi-team/attackathon-plume-network/blob/580cc6d61b08a728bd98f11b9a2140b84f41c802/arc/src/ArcTokenPurchase.sol#L439buyfunction revert due to insufficient balance:
https://github.com/immunefi-team/attackathon-plume-network/blob/580cc6d61b08a728bd98f11b9a2140b84f41c802/arc/src/ArcTokenPurchase.sol#L263
Proof of Concept
Setup
Token Admin calls enableToken to register a token for sale with totalAmountForSale = 500e18.
Withdraw unsold tokens
Token Admin calls withdrawUnsoldArcTokens to withdraw 50e18 tokens. (Contract token balance is now 450e18, but info.totalAmountForSale remains 500e18.)
Buyer queries available tokens
Buyer calls getMaxNumberOfTokens.
The function returns 500e18 (based on info.totalAmountForSale), which is higher than the actual balance.
Buy attempt fails
Buyer calls buy with amount 500e18.
The buy call reverts due to ContractBalanceInsufficient.