Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

228 Adding StakingRewardsPerEpoch contract #237

Closed
wants to merge 37 commits into from

Conversation

GoldenSylph
Copy link
Contributor

Changes

  • Added the generic contract for staking using epoch mechanism.

Automated Version Bump and others added 30 commits March 6, 2022 08:10
* adding hot fix

* fix typo

* Add test for hotfix

* fixing naming of the governance staking contract

* adding test

* adding test

* removing openzeppelin

* moving test

* removing unnecessary tests

* Apply suggestions from code review

* Revert "removing openzeppelin"

This reverts commit 39e120c.

* revert: openzeppelin files

* fix: hardhat config

Co-authored-by: Shloyem <[email protected]>
Co-authored-by: sirpy <[email protected]>
* Add GDX recalculation for TokenPurchased

* adding new airdrop calculation and staging

* Add new holders info to previous airdrop

* Add correct merkle tree generation

* Fix for exchange purchases not recorded

* Comments fixes

Co-authored-by: Oleg Bedrin <[email protected]>
* Add stakers gd rewards summing script

* add: use gdx mint/burn

Co-authored-by: sirpy <[email protected]>
@GoldenSylph GoldenSylph linked an issue Mar 30, 2022 that may be closed by this pull request
Comment on lines 44 to 49
constructor(address _rewardsToken, address _stakingToken) {
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
_setupRole(GUARDIAN_ROLE, msg.sender);
rewardsToken = IERC20(_rewardsToken);
stakingToken = IERC20(_stakingToken);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need for that, this contract should not handle token transfers

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done removal

Comment on lines 79 to 89
function recoverERC20(address tokenAddress, uint256 tokenAmount)
external
onlyRole(GUARDIAN_ROLE)
{
require(
tokenAddress != address(stakingToken),
"Cannot withdraw the staking token"
);
IERC20(tokenAddress).safeTransfer(msg.sender, tokenAmount);
emit Recovered(tokenAddress, tokenAmount);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should not be in this contract

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed

stakersInfo[_from].balance -= _amount;
}

stakingToken.safeTransfer(_from, _amount);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should not do any transfers

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

}

stakingToken.safeTransfer(_from, _amount);
emit Withdrawn(_from, _amount);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add epoch index to ALL events

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added

pendingStakes += _amount;
stakersInfo[_from].pendingStake += _amount;
stakersInfo[_from].indexOfLastEpochStaked = lastEpochIndex;
stakingToken.safeTransferFrom(_from, address(this), _amount);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no token transfers

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

uint256 reward = stakersInfo[_to].reward;
if (reward > 0) {
stakersInfo[_to].reward = 0;
rewardsToken.safeTransfer(_to, reward);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no token transfers

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

}

function _notifyRewardAmount(uint256 reward) internal {
totalSupply += pendingStakes;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldnt total supply be updated AFTER we calculate the rewardsPerToken?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

}

function _addPendingStakesToBalanceOnTimeUpdate(address _account) internal {
if (stakersInfo[_account].indexOfLastEpochStaked != lastEpochIndex) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also check if staker pendingStake > 0

import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

contract StakingRewardsPerEpoch is AccessControl, ReentrancyGuard, Pausable {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need for accesscontrol

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed

event RewardPaid(address indexed user, uint256 reward);
event Recovered(address token, uint256 amount);

bytes32 public constant GUARDIAN_ROLE = keccak256("GUARDIAN_ROLE");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need for guardian here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed

Comment on lines 45 to 46
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
_setupRole(GUARDIAN_ROLE, msg.sender);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need for roles

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed

Comment on lines 28 to 29
IERC20 public rewardsToken;
IERC20 public stakingToken;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not required

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed

stakersInfo[_account].reward = earned(_account);
}

function _notifyRewardAmount(uint256 reward) internal {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is reward? the newly earned rewards for the stakers?
if so rewardsPerToken is not calculated correctly. rewardsPerToken should be rewardsPerTokenSoFar+newReward/totalProductivity
see original synthetix
https://github.com/Synthetixio/synthetix/blob/89aa38664906b4f08fd393937f7f4e4ebdf267ef/contracts/StakingRewards.sol#L66

import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

contract StakingRewardsPerEpoch is AccessControl, ReentrancyGuard, Pausable {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move file to staking/utils instead of staking/fuse/utils

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -0,0 +1,146 @@
// SPDX-License-Identifier: MIT
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add comments to all methods (see how we comment in our smart contracts)
Add inline comments explaining all calculations

emit Recovered(tokenAddress, tokenAmount);
}

function _addPendingStakesToBalanceOnTimeUpdate(address _account) internal {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

method name could be more precise, what is timeupdate? we have epochs

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@sirpy sirpy requested a review from Shloyem May 10, 2022 14:36
&& stakersInfo[_account].pendingStake > 0) {
stakersInfo[_account].balance += stakersInfo[_account].pendingStake;
stakersInfo[_account].pendingStake = 0;
pendingStakes -= stakersInfo[_account].pendingStake;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs to come before the line above
stakersInfo[_account].pendingStake = 0;
or we will subtract 0

function _withdraw(address _from, uint256 _amount) internal virtual {
// if there are any pending stake for _from
if (stakersInfo[_from].pendingStake > 0) {
// if requested sum to withdraw is higher than actual pending stake balance
Copy link
Contributor

@Shloyem Shloyem May 10, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Opposite. If pending stakes are higher or equal to requested withdrawal amount than subtract the whole amount, otherwise subtract just whatever pending stake there is

emit Staked(_from, _amount, lastEpochIndex);
}

function _getReward(address _to) internal virtual returns(uint256 reward) {
Copy link
Contributor

@Shloyem Shloyem May 10, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is internal, but I don't see we call it anywhere. Reward is subtracted from user but not sent... we better discuss it

}

/**
* @dev A classic ERC20 method that allows staker balance acquiring.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @dev A classic ERC20 method that allows staker balance acquiring.
* @dev A classic ERC20 method that allows staker balance querying.

view
returns (uint256)
{
// The userEpochIndex is used to calculate a reward per toker per epoch
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// The userEpochIndex is used to calculate a reward per toker per epoch
// The userEpochIndex is used to calculate a reward per token per epoch

}

function _addPendingStakesToBalanceOnEpoch(address _account) internal {
// If stakers balance weren't updated when he staked and the staked
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// If stakers balance weren't updated when he staked and the staked
// If stakers balance wasn't updated when he staked and the staked

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Generic contract for rewards distribution logic
3 participants