On October 24th, 2024, the Ramses Exchange (@RamsesExchange) on Arbitrum suffered a loss of nearly $93,000 due to a flaw in its reward distribution logic. The vulnerability allowed the attacker to repeatedly claim rewards across multiple tokenIds without a corresponding reduction in the total rewards supply. By depositing tokens and invoking getPeriodReward() with different NFTs, the attacker drained reward pools, exploiting the contract’s failure to adequately track reward limits per period. The exploit primarily targeted accumulated incentives and fees rather than the underlying liquidity provider funds.
Fig: Attack Transaction
The root cause is that the FeeDistributor contract did not decrease tokenTotalSupplyByPeriod after each reward claim, resulting in an inflated total reward supply. This oversight allowed repeated reward calculations from the same supply, leading to excess distributions.
Fig: Root Cause in FeeDistributor
In the _getReward()
function, rewards for each NFT tokenId are calculated as a proportion of the tokenTotalSupplyByPeriod
, based on the NFT’s share ( veShareByPeriod[period][tokenId] ). This means that the higher the total supply, the higher the reward calculation for subsequent claims. However, tokenTotalSupplyByPeriod remains constant even after rewards are claimed, causing unintended excess in available rewards for subsequent claims.
Fig: resetting/splitting into new tokenID The attacker exploited this flaw by depositing tokens using an NFT, claiming rewards, and then resetting or splitting the NFT into a new tokenId (e.g., 18785 to 18787). This reset action allowed them to bypass the claim-tracking variable veWithdrawnTokenAmountByPeriod and repeatedly claim rewards as if they were distinct NFTs, despite having already claimed rewards in that period.
Since veWithdrawnTokenAmountByPeriod tracks withdrawn amounts per tokenId, the attacker could use multiple new tokenIds to exploit the inflated tokenTotalSupplyByPeriod without triggering restrictions. Thus, the attacker maximized reward claims across various NFTs while circumventing the withdrawal history check.
Fig: misconfig in period values The getPeriodReward() function does not verify if the specified period aligns with the current time. By specifying arbitrary period values, the attacker could access previously unclaimed rewards from earlier periods. This oversight in timestamp validation enabled them to retroactively claim inflated rewards that should have been restricted to active periods only.
Fig: Multiple getPeriodReward Calls Without validating period against the current period, rewards could be drained retroactively. This design flaw compounded with the inflated tokenTotalSupplyByPeriod, allowing the attacker to drain significant rewards using repeated claims.
This attack was first reported by BlockSec Phalcon (@Phalcon_xyz) on X in this post.
Fig: Ramses’s Discord Announcement Ramses’ Team has also acknowledged the attack and made an announcement that states,“First and most importantly, funds are safe. Liquidity provider funds are safe. User veNFT positions are safe.”
Ensure that tokenTotalSupplyByPeriod is updated appropriately after each reward claim. This could involve decrementing the total supply by the amount of rewards distributed to prevent inflated calculations in future claims.
Introduce a nonce or a mapping that tracks the number of claims per tokenId. This would prevent the same token ID from claiming rewards multiple times within the same period
Implement a nonce mechanism for every claim transaction. Each user or token should have a unique nonce that increments with each successful claim. This ensures that any replayed or duplicate transactions will be invalid since the nonce would not match the expected value.
To prevent such vulnerabilities, the best Smart Contract auditors must examine the Smart Contracts for logical issues. We at CredShields provide smart contract security and end-to-end security of web applications and externally exposed networks. Our public audit reports can be found on https://github.com/Credshields/audit-reports. Schedule a call at https://credshields.com/
Scan your Solidity contracts against the latest common security vulnerabilities with 280+ detections at SolidityScan.
Fig: SolidityScan — Smart Contract Vulnerability Scanner