Skip to content

Commit

Permalink
Add Scalar to index calculations
Browse files Browse the repository at this point in the history
  • Loading branch information
akshatmittal committed May 7, 2024
1 parent 8286472 commit 68bab44
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 25 deletions.
10 changes: 5 additions & 5 deletions contracts/rewards/GenericMultiRewardsVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.s
import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import { Math } from "@openzeppelin/contracts/utils/math/Math.sol";

import { RewardInfo, Errors, Events } from "./definitions.sol";
import { RewardInfo, Errors, Events, SCALAR } from "./definitions.sol";

/**
* @title GenericMultiRewardsVault
Expand Down Expand Up @@ -158,7 +158,7 @@ contract GenericMultiRewardsVault is ERC4626, Ownable {
rewardsEndTimestamp: rewardsEndTimestamp,
lastUpdatedTimestamp: SafeCast.toUint48(block.timestamp),
rewardsPerSecond: rewardsPerSecond,
index: ONE,
index: ONE * SCALAR,
ONE: ONE
});
distributorInfo[rewardToken] = distributor;
Expand Down Expand Up @@ -325,7 +325,7 @@ contract GenericMultiRewardsVault is ERC4626, Ownable {

if (supplyTokens != 0) {
// {qRewardTok} = {qRewardTok} * {qShare} / {qShare}
deltaIndex = (accrued * uint256(10 ** decimals())) / supplyTokens;
deltaIndex = (accrued * uint256(10 ** decimals()) * SCALAR) / supplyTokens;
}

// {qRewardTok} += {qRewardTok}
Expand All @@ -344,14 +344,14 @@ contract GenericMultiRewardsVault is ERC4626, Ownable {
// If user hasn't yet accrued rewards, grant them interest from the strategy beginning if they have a balance
// Zero balances will have no effect other than syncing to global index
if (oldIndex == 0) {
oldIndex = rewardIndex.ONE;
oldIndex = rewardIndex.ONE * SCALAR;
}

uint256 deltaIndex = rewardIndex.index - oldIndex;

// Accumulate rewards by multiplying user tokens by rewardsPerToken index and adding on unclaimed
// {qRewardTok} = {qShare} * {qRewardTok} / {qShare}
uint256 supplierDelta = (balanceOf(_user) * deltaIndex) / uint256(10 ** decimals());
uint256 supplierDelta = (balanceOf(_user) * deltaIndex) / uint256(10 ** decimals()) / SCALAR;

// {qRewardTok} += {qRewardTok}
accruedRewards[_user][_rewardToken] += supplierDelta;
Expand Down
2 changes: 2 additions & 0 deletions contracts/rewards/definitions.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ pragma solidity 0.8.24;

import { IERC20 } from "@openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol";

uint256 constant SCALAR = 1e18;

struct RewardInfo {
uint8 decimals; // Reward Token Decimals
uint48 rewardsEndTimestamp; // {s} Rewards End Timestamp; 0 = instant
Expand Down
40 changes: 20 additions & 20 deletions test/GenericMultiRewardsVault.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { ERC20Mock } from "@test/mocks/ERC20Mock.sol";

import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol";

import { GenericMultiRewardsVault, IERC20, IERC20Metadata } from "@src/rewards/GenericMultiRewardsVault.sol";
import { GenericMultiRewardsVault, IERC20, IERC20Metadata, SCALAR } from "@src/rewards/GenericMultiRewardsVault.sol";
import { Errors, Events } from "@src/rewards/definitions.sol";

// Test Suite based on Popcorn DAO's MultiRewardStaking
Expand Down Expand Up @@ -224,7 +224,7 @@ contract GenericMultiRewardsVaultTest is Test {
(, , uint48 lastUpdatedTimestamp, , uint256 index, uint256 ONE) = staking.rewardInfos(iRewardToken1);
// console2.log(index);
// console2.log("ts", staking.totalSupply());
assertEq(uint256(index), 2 * ONE);
assertEq(uint256(index), 2 * ONE * SCALAR);
assertEq(uint256(lastUpdatedTimestamp), callTimestamp);

assertEq(staking.userIndex(alice, iRewardToken1), index);
Expand All @@ -238,7 +238,7 @@ contract GenericMultiRewardsVaultTest is Test {
staking.mint(2 ether, alice);

(, , lastUpdatedTimestamp, , index, ) = staking.rewardInfos(iRewardToken1);
assertEq(uint256(index), (25 * ONE) / 10);
assertEq(uint256(index), (25 * ONE * SCALAR) / 10);
assertEq(uint256(lastUpdatedTimestamp), callTimestamp);

assertEq(staking.userIndex(alice, iRewardToken1), index);
Expand All @@ -251,7 +251,7 @@ contract GenericMultiRewardsVaultTest is Test {
staking.withdraw(2 ether, alice, alice);

(, , lastUpdatedTimestamp, , index, ) = staking.rewardInfos(iRewardToken1);
assertEq(uint256(index), (425 * ONE) / 100);
assertEq(uint256(index), (425 * ONE * SCALAR) / 100);
assertEq(uint256(lastUpdatedTimestamp), callTimestamp);

assertEq(staking.userIndex(alice, iRewardToken1), index);
Expand All @@ -264,7 +264,7 @@ contract GenericMultiRewardsVaultTest is Test {
staking.redeem(1 ether, alice, alice);

(, , lastUpdatedTimestamp, , index, ) = staking.rewardInfos(iRewardToken1);
assertEq(uint256(index), (475 * ONE) / 100);
assertEq(uint256(index), (475 * ONE * SCALAR) / 100);
assertEq(uint256(lastUpdatedTimestamp), callTimestamp);

assertEq(staking.userIndex(alice, iRewardToken1), index);
Expand All @@ -288,7 +288,7 @@ contract GenericMultiRewardsVaultTest is Test {
(, , uint48 lastUpdatedTimestampReward1, , uint256 indexReward1, uint256 reward1ONE) = staking.rewardInfos(
iRewardToken1
);
assertEq(uint256(indexReward1), 2 * reward1ONE);
assertEq(uint256(indexReward1), 2 * reward1ONE * SCALAR);
assertEq(uint256(lastUpdatedTimestampReward1), callTimestamp);

assertEq(staking.userIndex(alice, iRewardToken1), indexReward1);
Expand All @@ -306,7 +306,7 @@ contract GenericMultiRewardsVaultTest is Test {

// RewardsToken 1 -- 20% accrued
(, , lastUpdatedTimestampReward1, , indexReward1, ) = staking.rewardInfos(iRewardToken1);
assertEq(uint256(indexReward1), (25 * reward1ONE) / 10);
assertEq(uint256(indexReward1), (25 * reward1ONE * SCALAR) / 10);
assertEq(uint256(lastUpdatedTimestampReward1), callTimestamp);

assertEq(staking.userIndex(alice, iRewardToken1), indexReward1);
Expand All @@ -316,7 +316,7 @@ contract GenericMultiRewardsVaultTest is Test {
(, , uint48 lastUpdatedTimestampReward2, , uint256 indexReward2, uint256 reward2ONE) = staking.rewardInfos(
iRewardToken2
);
assertEq(uint256(indexReward2), (15 * reward2ONE) / 10);
assertEq(uint256(indexReward2), (15 * reward2ONE * SCALAR) / 10);
assertEq(uint256(lastUpdatedTimestampReward2), callTimestamp);

assertEq(staking.userIndex(alice, iRewardToken2), indexReward2);
Expand All @@ -329,15 +329,15 @@ contract GenericMultiRewardsVaultTest is Test {

// RewardsToken 1 -- 100% accrued
(, , lastUpdatedTimestampReward1, , indexReward1, ) = staking.rewardInfos(iRewardToken1);
assertEq(uint256(indexReward1), (45 * reward1ONE) / 10);
assertEq(uint256(indexReward1), (45 * reward1ONE * SCALAR) / 10);
assertEq(uint256(lastUpdatedTimestampReward1), callTimestamp);

assertEq(staking.userIndex(alice, iRewardToken1), indexReward1);
assertEq(staking.accruedRewards(alice, iRewardToken1), 10 * reward1ONE);

// RewardsToken 2 -- 90% accrued
(, , lastUpdatedTimestampReward2, , indexReward2, ) = staking.rewardInfos(iRewardToken2);
assertEq(uint256(indexReward2), (35 * reward2ONE) / 10);
assertEq(uint256(indexReward2), (35 * reward2ONE * SCALAR) / 10);
assertEq(uint256(lastUpdatedTimestampReward2), callTimestamp);

assertEq(staking.userIndex(alice, iRewardToken2), indexReward2);
Expand Down Expand Up @@ -365,7 +365,7 @@ contract GenericMultiRewardsVaultTest is Test {
(, , uint48 lastUpdatedTimestamp, , uint256 index, uint256 ONE) = staking.rewardInfos(iRewardToken1);
assertEq(rewardToken1.balanceOf(alice), 1 * ONE);

assertEq(uint256(index), 2 * ONE);
assertEq(uint256(index), 2 * ONE * SCALAR);
assertEq(uint256(lastUpdatedTimestamp), callTimestamp);

assertEq(staking.userIndex(alice, iRewardToken1), index);
Expand All @@ -389,7 +389,7 @@ contract GenericMultiRewardsVaultTest is Test {
staking.deposit(1 ether, alice);

(, , uint48 lastUpdatedTimestamp, , uint256 index, uint256 ONE) = staking.rewardInfos(iRewardToken1);
assertEq(uint256(index), 11 * ONE);
assertEq(uint256(index), 11 * ONE * SCALAR);
assertEq(uint256(lastUpdatedTimestamp), callTimestamp);

assertEq(staking.userIndex(alice, iRewardToken1), index);
Expand All @@ -403,7 +403,7 @@ contract GenericMultiRewardsVaultTest is Test {
staking.withdraw(1 ether, alice, alice);

(, , lastUpdatedTimestamp, , index, ) = staking.rewardInfos(iRewardToken1);
assertEq(uint256(index), 11 * ONE);
assertEq(uint256(index), 11 * ONE * SCALAR);
assertEq(uint256(lastUpdatedTimestamp), callTimestamp);

assertEq(staking.userIndex(alice, iRewardToken1), index);
Expand All @@ -426,7 +426,7 @@ contract GenericMultiRewardsVaultTest is Test {

(, , uint48 lastUpdatedTimestamp, , uint256 index, uint256 ONE) = staking.rewardInfos(iRewardToken1);
// Accrual doesnt start until someone deposits -- TODO does this change some of the rewardsEnd and rewardsSpeed assumptions?
assertEq(uint256(index), 1 * ONE);
assertEq(uint256(index), 1 * ONE * SCALAR);
assertEq(uint256(lastUpdatedTimestamp), callTimestamp);

assertEq(staking.userIndex(alice, iRewardToken1), index);
Expand All @@ -439,7 +439,7 @@ contract GenericMultiRewardsVaultTest is Test {
staking.mint(2 ether, bob);

(, , lastUpdatedTimestamp, , index, ) = staking.rewardInfos(iRewardToken1);
assertEq(uint256(index), 2 * ONE);
assertEq(uint256(index), 2 * ONE * SCALAR);
assertEq(uint256(lastUpdatedTimestamp), callTimestamp);

assertEq(staking.userIndex(alice, iRewardToken1), index);
Expand All @@ -458,7 +458,7 @@ contract GenericMultiRewardsVaultTest is Test {
staking.withdraw((5 * ONE) / 10, bob, bob);

(, , lastUpdatedTimestamp, , index, ) = staking.rewardInfos(iRewardToken1);
assertEq(uint256(index), ONE + (ONE * 10) / 3);
assertEq(uint256(index), ONE * SCALAR + (ONE * 10 * SCALAR) / 3);
assertEq(uint256(lastUpdatedTimestamp), callTimestamp);

assertEq(staking.userIndex(alice, iRewardToken1), index);
Expand Down Expand Up @@ -518,7 +518,7 @@ contract GenericMultiRewardsVaultTest is Test {
assertEq(uint256(ONE), 10 ** decimals);
assertEq(rewardsPerSecond, 0.1 ether);
assertEq(uint256(rewardsEndTimestamp), callTimestamp + 100);
assertEq(index, ONE);
assertEq(index, ONE * SCALAR);
assertEq(uint256(lastUpdatedTimestamp), callTimestamp);

// Confirm token transfer
Expand All @@ -544,7 +544,7 @@ contract GenericMultiRewardsVaultTest is Test {
assertEq(uint256(ONE), 10 ** decimals);
assertEq(rewardsPerSecond, 0);
assertEq(uint256(rewardsEndTimestamp), callTimestamp);
assertEq(index, ONE);
assertEq(index, ONE * SCALAR);
assertEq(uint256(lastUpdatedTimestamp), callTimestamp);
}

Expand Down Expand Up @@ -643,7 +643,7 @@ contract GenericMultiRewardsVaultTest is Test {

// Check Alice RewardsState
(, , uint48 lastUpdatedTimestamp, , uint256 index, ) = staking.rewardInfos(iRewardToken1);
assertEq(uint256(index), 5 * ONE);
assertEq(uint256(index), 5 * ONE * SCALAR);

assertEq(staking.userIndex(alice, iRewardToken1), index);
assertEq(staking.accruedRewards(alice, iRewardToken1), 4 * ONE);
Expand All @@ -653,7 +653,7 @@ contract GenericMultiRewardsVaultTest is Test {

// Check Bobs RewardsState
(, , lastUpdatedTimestamp, , index, ) = staking.rewardInfos(iRewardToken1);
assertEq(uint256(index), 5 * ONE);
assertEq(uint256(index), 5 * ONE * SCALAR);

assertEq(staking.userIndex(bob, iRewardToken1), index);
assertEq(staking.accruedRewards(bob, iRewardToken1), 1 * ONE);
Expand Down

0 comments on commit 68bab44

Please sign in to comment.