Fix rewards accrual bug mentioned by T-Hax: in 'accrueOldRewards' function we added rewards that staker hasn't earned, because 'checkReward' function in Staking contract returns updated (actual) reward amount, but not update it in storage. Replace 'checkReward' function with getter 'accumulatedRewards', which returns actual accumulated reward amount (not updated)

This commit is contained in:
Theo 2023-06-12 16:45:32 -07:00
parent 861f4cddaf
commit 79d5bfd103
4 changed files with 20 additions and 6 deletions

@ -5,7 +5,7 @@
"scripts": {
"computeRewards": "npx ts-node scripts/writeStakersData.ts",
"test": "forge test -vvv --fork-url https://rpc.mevblocker.io --fork-block-number 17466009",
"testGas": "forge test -vvv --fork-url https://rpc.mevblocker.io --fork-block-number 17466009 --gas-report"
"testGas": "forge test -vvv --fork-url https://rpc.mevblocker.io --gas-report"
},
"repository": {
"type": "git",

@ -22,7 +22,7 @@ contract RestoreRewardsProposal {
function accrueOldReward(address stakerAddress, uint256 oldRewards) internal {
ITornadoStakingRewards staking = ITornadoStakingRewards(stakingProxyAddress);
staking.setReward(stakerAddress, staking.checkReward(stakerAddress) + oldRewards);
staking.setReward(stakerAddress, staking.accumulatedRewards(stakerAddress) + oldRewards);
}
function executeProposal() external {

@ -11,4 +11,6 @@ interface ITornadoStakingRewards {
function setReward(address account, uint256 amount) external;
function checkReward(address account) external view returns (uint256);
function accumulatedRewards(address account) external view returns (uint256);
}

@ -13,6 +13,18 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
contract TestProposal is MockProposal {
ITornadoStakingRewards staking = ITornadoStakingRewards(_stakingAddress);
function testGovernanceBalance() internal {
IERC20 TORN = IERC20(_tokenAddress);
uint256 governanceBalanceBeforeExecution = TORN.balanceOf(_governanceAddress);
console2.log("Governance balance before proposal execution: %s TORN", governanceBalanceBeforeExecution / _tornDecimals);
createAndExecuteProposal();
uint256 governanceBalanceAfterExecution = TORN.balanceOf(_governanceAddress);
console2.log("Governance balance after proposal execution: %s TORN", governanceBalanceAfterExecution / _tornDecimals);
}
function testOtherUsersRewardUnchanged() public {
uint256 rewardsBeforeProposal = staking.checkReward(TEST_REAL_ADDRESS_WITH_BALANCE);
console2.log("Developer rewards before proposal execution: %s TORN", rewardsBeforeProposal);
@ -44,26 +56,26 @@ contract TestProposal is MockProposal {
function getStakersRewardsSum(Staker[385] memory stakers) internal returns (uint256) {
uint256 rewardsSum = 0;
for (uint16 i = 0; i < stakers.length; i++) {
rewardsSum += staking.checkReward(stakers[i].addr);
rewardsSum += staking.accumulatedRewards(stakers[i].addr);
}
return rewardsSum;
}
function testVerifyStakersAccrual() public {
function testVerifyStakersAccrual() internal {
Staker[385] memory stakers = getOldStakers();
uint256[385] memory rewardsBefore;
uint256[385] memory rewardsAfter;
for (uint16 i = 0; i < stakers.length; i++) {
rewardsBefore[i] = staking.checkReward(stakers[i].addr);
rewardsBefore[i] = staking.accumulatedRewards(stakers[i].addr);
}
createAndExecuteProposal();
for (uint16 i = 0; i < stakers.length; i++) {
rewardsAfter[i] = staking.checkReward(stakers[i].addr);
rewardsAfter[i] = staking.accumulatedRewards(stakers[i].addr);
}
for (uint16 i = 0; i < stakers.length; i++) {