Whenever a user Stakes their NFT , they are awarded reward in Ajna Tokens for Updating Bucket Exchange Rate as well as interest earned by keeping their NFT in the contract . While reviewing the RewardsManager.sol , the function _transferAjnaRewards caught my attention.
The problem is
if (rewardsEarned_ > ajnaBalance) rewardsEarned_ = ajnaBalance; , as it completely destroys the additiona extra reward tokens if the reward token exceeds the current ajnaBalance.
This can lead to griefing attacks where user's loose parts of their reward tokens as some malicious actor spreads some news and because of the impact of the news, everyone starts calling the contract at the same time to withdraw their rewards and NFTs .
Proof of Concept
Alice, John, and Caren and some 1000 more users have staked their NFT to the contract for a long time let's say 2 years or even more. They expect that they will get a huge amount of rewards from interest of Staking .
A Malicious actor Kevin has also staked his multiple NFT to the contract from a short time. He knows that he will get some good reward in tokens but his intentions are not about the rewards but to harm other users and cause their loss of reward.
What Kevin does is, He starts spreading fake news that the Ajna Contract will come to an end or maybe is closing or something.
All the user's start panicking as they fear that they will loose their NFT as well as Token Rewards.
All of them starts calling cliam() function to withdraw their rewards( through unstake() ).
Because of this, there comes a surge in reward claims as all users are simultaneously claiming the rewards.
Because of this, the ajnaBalance decreases and multiple users with huge rewards will start getting lose of rewards as if the rewardsEarned_ > ajnaBalance then rewardsEarned = ajnaBalance and all the remaining balance of rewardsEarned get's lost.
Tools Used
Manual Analysis
Recommended Mitigation Steps
It will be better if there is a check before calling the _transferAjnaRewards() to check for ajnaBalance and if it is less than rewardsEarned, the function does not get's called .
Another remediation would be to handle the rewardsEarned_ = ajnaBalance; with a different logic to prevent the reward tokens loss of users.
Lines of code
https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edceaaab7a5c3964/ajna-core/src/RewardsManager.sol#L815
Vulnerability details
Impact
Whenever a user Stakes their NFT , they are awarded reward in Ajna Tokens for Updating Bucket Exchange Rate as well as interest earned by keeping their NFT in the contract . While reviewing the
RewardsManager.sol
, the function_transferAjnaRewards
caught my attention. The problem isif (rewardsEarned_ > ajnaBalance) rewardsEarned_ = ajnaBalance;
, as it completely destroys the additiona extra reward tokens if the reward token exceeds the current ajnaBalance.https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edceaaab7a5c3964/ajna-core/src/RewardsManager.sol#L815
This can lead to griefing attacks where user's loose parts of their reward tokens as some malicious actor spreads some news and because of the impact of the news, everyone starts calling the contract at the same time to withdraw their rewards and NFTs .
Proof of Concept
ajnaBalance
decreases and multiple users with huge rewards will start getting lose of rewards as if therewardsEarned_ > ajnaBalance
thenrewardsEarned = ajnaBalance
and all the remaining balance ofrewardsEarned
get's lost.Tools Used
Manual Analysis
Recommended Mitigation Steps
It will be better if there is a check before calling the
_transferAjnaRewards()
to check forajnaBalance
and if it is less thanrewardsEarned
, the function does not get's called .Another remediation would be to handle the
rewardsEarned_ = ajnaBalance;
with a different logic to prevent the reward tokens loss of users.Assessed type
Other