Lucene search

K
code423n4Code4renaCODE423N4:2023-03-NEOTOKYO-FINDINGS-ISSUES-347
HistoryMar 15, 2023 - 12:00 a.m.

Wrong accounting of share leading to incorrect amount of BYTES be minted per second

2023-03-1500:00:00
Code4rena
github.com
4
neotokyostaker
reward calculation
emission rate
staking pools
vulnerability
admin configuration
proof of concept
mitigation steps.

Lines of code

Vulnerability details

Impact

In NeoTokyoStaker, staker is a competitive system where stakers compete for a fixed emission rate in each of the S1 Citizen, S2 Citizen, and LP token staking pools. For each staking pool, there are some reward windows. Each reward window has different emission rates configurable by admin. So when calculating the final reward amount for a user, it does a for loop through every reward window and sum them up.

However, it used the final points and totalPoints when staker claimed reward for every previous reward window, which is not correct since totalPoints is different every time other stakers deposit/withdraw.

The result is the reward is incorrectly calculated, it can be higher or lower than expected, and both cases are high risk issues.

Proof of Concept

Consider a scenario:

  1. Citizen S2 pools have 2 reward windows.
    The first starts at t1 = 100 and rate1 = 200, the second starts at t2 = 200 and rate2 = 300

  2. Alice and Bob both stakes at t0 = 100, Citizen S2 tokens have the same weight (100) so Alice and Bob should receive equal amounts of rewards at any moment.

  3. Alice withdraw first at t3 = 300, her share is equal to 100 and totalPoints = 200, she will receive

totalReward = ((t2 - t1) * rate1 + (t3 - t2) * rate2)
  = 100 * 200 + 100 * 300 = 50000
share = points * totalReward / totalPoints 
  = 100 * 50000 / 200 = 25000
totalPoints = 100
  1. Bob withdraw at the same time, but his TX is executed after Alice, he will receive
totalReward = ((t2 - t1) * rate1 + (t3 - t2) * rate2)
  = 100 * 200 + 100 * 300 = 50000
share = points * totalReward / totalPoints 
  = 100 * 50000 / 100 = 50000

As we can see, Alice and Bob both deposit and withdraw at the same time, but Alice only gets 25000 while Bob gets 50000 token reward.
Totally, they receive 75000 while totalReward is only 50000, which is more than expected amount of BYTES should be minted.

Tools Used

Manual Review

Recommended Mitigation Steps

Consider changing the formula to calculate rewards for users.
For example, in Master Chef, we need to calculate the accumulated reward rate per share of the pool every time a user interacts with the pool and only need to update the position of each user when they interact.


The text was updated successfully, but these errors were encountered:

All reactions