193 lines
9.1 KiB
Solidity
193 lines
9.1 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
|
|
pragma solidity ^0.6.12;
|
|
pragma experimental ABIEncoderV2;
|
|
|
|
import { MockProposal } from "./MockProposal.sol";
|
|
import { Staker, ITornadoStakingRewards } from "@interfaces/ITornadoStakingRewards.sol";
|
|
|
|
import { Test } from "@forge-std/Test.sol";
|
|
import "@forge-std/console2.sol";
|
|
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
|
|
contract TestProposal is MockProposal {
|
|
ITornadoStakingRewards staking = ITornadoStakingRewards(_stakingAddress);
|
|
|
|
function testGovernanceBalance() public {
|
|
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);
|
|
|
|
uint256 governanceBalanceDifference = governanceBalanceBeforeExecution - governanceBalanceAfterExecution;
|
|
console2.log("Governance balance difference: %s TORN, %s", governanceBalanceDifference / _tornDecimals, governanceBalanceDifference);
|
|
|
|
require(governanceBalanceDifference == summaryRestoreAmount, "Incorrect Governance balance after execution");
|
|
}
|
|
|
|
function testOtherUsersRewardUnchanged() public {
|
|
uint256 rewardsBeforeProposal = staking.checkReward(TEST_REAL_ADDRESS_WITH_BALANCE);
|
|
console2.log("Developer rewards before proposal execution: %s TORN", rewardsBeforeProposal / _tornDecimals);
|
|
|
|
createAndExecuteProposal();
|
|
|
|
uint256 rewardsAfterProposal = staking.checkReward(TEST_REAL_ADDRESS_WITH_BALANCE);
|
|
console2.log("Developer rewards after proposal execution: %s TORN", rewardsBeforeProposal / _tornDecimals);
|
|
|
|
require(rewardsAfterProposal == rewardsBeforeProposal, "Other stakers rewards changed");
|
|
}
|
|
|
|
function testCannotCallSetRewardsNotFromGovernance() public executeCurrentProposalBefore {
|
|
// Trying to set rewards to myself, expect error revert call
|
|
vm.startPrank(TEST_ADDRESS_ONE);
|
|
vm.expectRevert(bytes("only governance"));
|
|
staking.setReward(TEST_ADDRESS_ONE, 100_000 ether);
|
|
vm.stopPrank();
|
|
|
|
require(staking.checkReward(TEST_ADDRESS_ONE) == 0, "Rewards accrued without permissions (not from Governance call)");
|
|
|
|
vm.startPrank(_governanceAddress);
|
|
staking.setReward(TEST_ADDRESS_ONE, 100_000 ether);
|
|
vm.stopPrank();
|
|
|
|
require(staking.checkReward(TEST_ADDRESS_ONE) == 100_000 ether, "Rewards not accrued by Governance");
|
|
}
|
|
|
|
function getStakersRewardsSum(Staker[cheatingStakersCount] memory stakers) internal returns (uint256) {
|
|
uint256 rewardsSum = 0;
|
|
for (uint16 i = 0; i < stakers.length; i++) {
|
|
rewardsSum += staking.accumulatedRewards(stakers[i].addr);
|
|
}
|
|
|
|
return rewardsSum;
|
|
}
|
|
|
|
function testVerifyStakersAccrual() internal {
|
|
Staker[cheatingStakersCount] memory stakers = getOldStakers();
|
|
|
|
uint256[cheatingStakersCount] memory rewardsBefore;
|
|
uint256[cheatingStakersCount] memory rewardsAfter;
|
|
|
|
for (uint16 i = 0; i < stakers.length; i++) {
|
|
rewardsBefore[i] = staking.accumulatedRewards(stakers[i].addr);
|
|
}
|
|
|
|
createAndExecuteProposal();
|
|
|
|
for (uint16 i = 0; i < stakers.length; i++) {
|
|
rewardsAfter[i] = staking.accumulatedRewards(stakers[i].addr);
|
|
}
|
|
|
|
for (uint16 i = 0; i < stakers.length; i++) {
|
|
console2.log("\nStaker address: %s", stakers[i].addr);
|
|
console2.log("Rewards before: %s", rewardsBefore[i]);
|
|
console2.log("Rewards after: %s", rewardsAfter[i]);
|
|
console2.log("Real difference: %s", (rewardsAfter[i] - rewardsBefore[i]));
|
|
console2.log("Expected difference: %s", stakers[i].oldRewards);
|
|
require(rewardsAfter[i] - rewardsBefore[i] == stakers[i].oldRewards);
|
|
}
|
|
}
|
|
|
|
function testStakingContractReplenishedCorrect() public {
|
|
Staker[cheatingStakersCount] memory stakers = getOldStakers();
|
|
|
|
uint256 stakersRewardsSumBeforeExecution = getStakersRewardsSum(stakers);
|
|
console2.log("Old stakers rewards sum before proposal execution: %s TORN", stakersRewardsSumBeforeExecution / _tornDecimals);
|
|
|
|
uint256 stakingContractBalanceBeforeExecution = IERC20(_tokenAddress).balanceOf(_stakingAddress);
|
|
console2.log("Staking contract balance before proposal execution: %s TORN", stakingContractBalanceBeforeExecution / _tornDecimals);
|
|
|
|
createAndExecuteProposal();
|
|
|
|
uint256 stakersRewardsSumAfterExecution = getStakersRewardsSum(stakers);
|
|
console2.log("\nOld stakers rewards sum after proposal exectuion: %s TORN", stakersRewardsSumAfterExecution / _tornDecimals);
|
|
|
|
uint256 stakingContractBalanceAfterExecution = IERC20(_tokenAddress).balanceOf(_stakingAddress);
|
|
console2.log("Staking contract balance after proposal execution: %s TORN", stakingContractBalanceAfterExecution / _tornDecimals);
|
|
|
|
uint256 stakersRewardSumDifference = stakersRewardsSumAfterExecution - stakersRewardsSumBeforeExecution;
|
|
uint256 stakingContractBalanceDifference = stakingContractBalanceAfterExecution - stakingContractBalanceBeforeExecution;
|
|
|
|
console2.log("\nStaking contract replenish amount: %s TORN", stakingContractBalanceDifference / _tornDecimals);
|
|
console2.log("Stakers restored rewards sum: %s TORN", stakersRewardSumDifference / _tornDecimals);
|
|
|
|
require(
|
|
stakersRewardSumDifference == stakingContractBalanceDifference,
|
|
"Staking replenish sum doesn't match with stakers restored rewards sum"
|
|
);
|
|
}
|
|
|
|
function testAccumulatedRewardPerTornNotChanged() public {
|
|
uint256 accumulatedRewardsPerTornBeforeExecution = staking.accumulatedRewardPerTorn();
|
|
console2.log("Accumulated reward per 1 TORN before proposal execution: %s", accumulatedRewardsPerTornBeforeExecution / _tornMaximumSupply);
|
|
|
|
createAndExecuteProposal();
|
|
|
|
|
|
uint256 accumulatedRewardsPerTornAfterExecution = staking.accumulatedRewardPerTorn();
|
|
console2.log("Accumulated reward per 1 TORN after proposal execution: %s", accumulatedRewardsPerTornAfterExecution / _tornMaximumSupply);
|
|
|
|
require(accumulatedRewardsPerTornBeforeExecution == accumulatedRewardsPerTornAfterExecution, "Accumulater reward per TORN changed");
|
|
}
|
|
|
|
function testRewardAccrualsMechanismCorrect() public executeCurrentProposalBefore {
|
|
IERC20 TORN = IERC20(_tokenAddress);
|
|
|
|
uint256 toBurn = 10_000 ether;
|
|
|
|
retrieveAndLockBalance(TEST_STAKER_PRIVATE_KEY, TEST_STAKER_ADDRESS, PROPOSAL_THRESHOLD);
|
|
uint256 stakerLockedBalance = governance.lockedBalance(TEST_STAKER_ADDRESS);
|
|
require(stakerLockedBalance == PROPOSAL_THRESHOLD, "Invalid test staker locked balance");
|
|
|
|
uint256 stakerRewardsBeforeBurning = staking.checkReward(TEST_STAKER_ADDRESS);
|
|
console2.log("Staking rewards before burning: %s TORN", stakerRewardsBeforeBurning / _tornDecimals);
|
|
|
|
burnTokens(_governanceAddress, toBurn, staking);
|
|
|
|
uint256 stakerRewardsAfterBurning = staking.checkReward(TEST_STAKER_ADDRESS);
|
|
console2.log(
|
|
"Staking rewards after burning 10 000 TORN: %s TORN\n", stakerRewardsAfterBurning / _tornDecimals
|
|
);
|
|
require(stakerRewardsAfterBurning > stakerRewardsBeforeBurning, "Rewards isn't changed after burning");
|
|
|
|
// All TORN, locked by users in Governance, is on the userVault contract balance
|
|
uint256 governanceLockedAmount = TORN.balanceOf(governance.userVault());
|
|
uint256 receivedReward = stakerRewardsAfterBurning - stakerRewardsBeforeBurning;
|
|
uint256 expectedRewards = stakerLockedBalance * toBurn / governanceLockedAmount;
|
|
|
|
console2.log("Expected staking rewards: %s TORN", expectedRewards / _tornDecimals);
|
|
console2.log("Staker received rewards: %s TORN\n", receivedReward / _tornDecimals);
|
|
|
|
require(receivedReward == expectedRewards, "Expected and received rewards don't match");
|
|
}
|
|
|
|
function testAccumulatedRewardCanBeUpdated() public executeCurrentProposalBefore {
|
|
uint256 accumulatedRewardPerTornBeforeBurning =
|
|
staking.accumulatedRewardPerTorn() / _tornMaximumSupply;
|
|
|
|
console2.log(
|
|
"Accumulated reward per TORN right after proposal execution: %s TORN",
|
|
accumulatedRewardPerTornBeforeBurning / _tornDecimals
|
|
);
|
|
|
|
burnTokens(_governanceAddress, 10_000_000 ether, staking);
|
|
|
|
uint256 accumulatedRewardPerTornAfterBurning = staking.accumulatedRewardPerTorn() / _tornMaximumSupply;
|
|
|
|
console2.log(
|
|
"Accumulated reward per TORN after burning 10 000 000 TORN: ~ %s TORN",
|
|
accumulatedRewardPerTornAfterBurning / _tornDecimals
|
|
);
|
|
|
|
require(
|
|
accumulatedRewardPerTornAfterBurning > accumulatedRewardPerTornBeforeBurning,
|
|
"Staking rewards isn't updated"
|
|
);
|
|
}
|
|
}
|