Contract fails to deliver promised returns, but doesn't lose value
Description
Brief/Intro
The ArcTokenPurchase contract contains an accounting flaw where withdrawing unsold tokens via withdrawUnsoldArcTokens() does not update the internal TokenInfo state variables used to track remaining sale inventory. This creates a permanent mismatch between the reported number of tokens available (getMaxNumberOfTokens) and the actual token balance in the contract. As a result, buyers will be shown incorrect availability and any attempted purchases after such a withdrawal will fail, effectively halting the sale and misleading participants.
Vulnerability Details
The contract tracks token sale data in the TokenInfo struct, where totalAmountForSale and amountSold are used to compute availability via:
functiongetMaxNumberOfTokens(address_tokenContract)externalviewreturns(uint256){ TokenInfo storage info =_getPurchaseStorage().tokenInfo[_tokenContract];return info.totalAmountForSale - info.amountSold;}
However, the withdrawUnsoldArcTokens() function transfers tokens out without adjusting totalAmountForSale or amountSold:
Because getMaxNumberOfTokens() reads from stale state, the reported availability remains unchanged after withdrawals, even when the contract’s balance is depleted.
Example (Observed in Test)
Before withdrawal:
Reported remaining tokens: 500
Actual balance: 500
After withdrawal of all 500:
Reported remaining tokens: 500 (stale)
Actual balance: 0
Any subsequent purchase will revert due to:
but UIs or off-chain systems relying on getMaxNumberOfTokens will still display the stale 500 tokens as available.
Impact Details
Denial of Service: All further purchases will fail after an unsold token withdrawal, halting sales completely.
False Reporting / Market Manipulation Risk: Off-chain systems and frontends using getMaxNumberOfTokens will misrepresent sale inventory, misleading users into believing tokens remain for sale.
Loss of Revenue: The project may lose potential buyers due to perceived availability followed by transaction failures.