Conversation
1ebf180 to
4276123
Compare
2946aca to
f14ffae
Compare
| @@ -0,0 +1,12 @@ | |||
| pragma solidity ^0.6.6; | |||
|
|
|||
| abstract contract RewardsDistributionRecipient { | |||
There was a problem hiding this comment.
out of the box contract
|
|
||
| // forked from https://github.com/SetProtocol/index-coop-contracts/blob/master/contracts/staking/StakingRewardsV2.sol | ||
| // NOTE: V2 allows setting of rewardsDuration in constructor | ||
| contract StakingRewardsV2 is RewardsDistributionRecipient, ReentrancyGuard { |
There was a problem hiding this comment.
out of the box contract with a minor change
| // Added to support recovering LP Rewards from other systems such as BAL to be distributed to holders | ||
| function recoverERC20(address tokenAddress, address to, uint256 tokenAmount) external onlyRewardsDistribution { | ||
| require(tokenAddress != address(stakingToken), "Cannot withdraw the staking token"); | ||
| require(tokenAddress != address(rewardsToken), "Cannot withdraw the rewards token"); | ||
|
|
||
| IERC20(tokenAddress).safeTransfer(to, tokenAmount); | ||
| emit Recovered(tokenAddress, to, tokenAmount); | ||
| } |
There was a problem hiding this comment.
Added this method from StakingRewards v1
| import "./IDOInterface.sol"; | ||
| import "../utils/Timed.sol"; | ||
| import "../refs/CoreRef.sol"; | ||
| import "../pool/IPool.sol"; |
There was a problem hiding this comment.
removed Pool init logic because now we can simply drip publicly from the FeiRewardsDistributor post the first dripFrequency window. This removes the risk of the new stakingRewards contract bricking launch
|
|
||
| uint256 public constant POOL_DURATION = 2 * 365 days; | ||
| uint256 public constant THAWING_DURATION = 4 weeks; | ||
| uint256 public constant DRIP_FREQUENCY = 1 weeks; |
There was a problem hiding this comment.
This is both the frequency with which FeiRewardsDistributor can drip and the expected duration of FeiStakingRewards
| core.grantMinter(feiRewardsDistributor); | ||
|
|
||
| IRewardsDistributor(feiRewardsDistributor).setStakingContract(feiStakingRewards); | ||
|
|
There was a problem hiding this comment.
set the distributor as a minter to incentivize drips, and complete the wiring
| pragma solidity ^0.6.0; | ||
|
|
||
| import "@openzeppelin/contracts/access/Ownable.sol"; | ||
| import "../pool/FeiPool.sol"; |
There was a problem hiding this comment.
remove pool from this orchestrator to make a separate one
| /// @title A StakingRewards contract for earning TRIBE with staked FEI/TRIBE LP tokens | ||
| /// @author Fei Protocol | ||
| /// @notice deposited LP tokens will earn TRIBE over time at a linearly decreasing rate | ||
| contract FeiStakingRewards is StakingRewardsV2 { |
There was a problem hiding this comment.
simple wrapper around StakingRewardsV2, not really necessary
| /// @notice the total amount of rewards owned by contract and unlocked for release | ||
| function releasedReward() public view override returns (uint256) { | ||
| uint256 total = rewardBalance(); | ||
| uint256 unreleased = unreleasedReward(); | ||
| return total.sub(unreleased, "Pool: Released Reward underflow"); | ||
| } | ||
|
|
||
| /// @notice the total amount of rewards distributed by the contract over entire period | ||
| function totalReward() public view override returns (uint256) { | ||
| return rewardBalance().add(distributedRewards); | ||
| } | ||
|
|
||
| /// @notice the total balance of rewards owned by contract, locked or unlocked | ||
| function rewardBalance() public view override returns (uint256) { | ||
| return tribeBalance(); | ||
| } | ||
|
|
||
| /// @notice the total amount of rewards owned by contract and locked | ||
| function unreleasedReward() public view override returns (uint256) { | ||
| if (isTimeEnded()) { | ||
| return 0; | ||
| } | ||
|
|
||
| return | ||
| _unreleasedReward( | ||
| totalReward(), | ||
| duration, | ||
| timeSinceStart() | ||
| ); | ||
| } | ||
|
|
||
| // Represents the integral of 2R/d - 2R/d^2 x dx from t to d | ||
| // Integral equals 2Rx/d - Rx^2/d^2 | ||
| // Evaluated at t = 2R*t/d (start) - R*t^2/d^2 (end) | ||
| // Evaluated at d = 2R - R = R | ||
| // Solution = R - (start - end) or equivalently end + R - start (latter more convenient to code) | ||
| function _unreleasedReward( | ||
| uint256 _totalReward, | ||
| uint256 _duration, | ||
| uint256 _time | ||
| ) internal pure returns (uint256) { | ||
| // 2R*t/d | ||
| Decimal.D256 memory start = | ||
| Decimal.ratio(_totalReward, _duration).mul(2).mul(_time); | ||
|
|
||
| // R*t^2/d^2 | ||
| Decimal.D256 memory end = | ||
| Decimal.ratio(_totalReward, _duration).div(_duration).mul( |
There was a problem hiding this comment.
audited logic from Pool.sol and FeiPool.sol for calculating the amount distributed over a window
| function drip() public override postGenesis returns(uint256) { | ||
| require(!killSwitch, "FeiRewardsDistributor: drip disabled"); | ||
|
|
||
| // solhint-disable-next-line not-rely-on-time | ||
| require(block.timestamp >= nextDripAvailable(), "FeiRewardsDistributor: Not passed drip frequency"); | ||
| // solhint-disable-next-line not-rely-on-time | ||
| lastDistributionTime = block.timestamp; | ||
|
|
||
| uint amount = releasedReward(); | ||
| require(amount != 0, "FeiRewardsDistributor: no rewards"); | ||
| distributedRewards = distributedRewards.add(amount); | ||
|
|
||
| tribe().transfer(address(stakingContract), amount); | ||
| stakingContract.notifyRewardAmount(amount); | ||
|
|
||
| _incentivize(); | ||
|
|
||
| emit Drip(msg.sender, amount); | ||
| return amount; | ||
| } |
There was a problem hiding this comment.
The main risk in the change is this method
Update the Pool contracts to use Synthetix StakingRewards instead.
Basically split out the pool logic related to stake, claim, withdraw and instead use
FeiStakingRewardswhich wrapsStakingRewardsV2. We can assume this contract works as intended.The risk is in
FeiRewardsDistributorwhich inherits the distribution schedule logic from the oldFeiPool + Poolcontracts. The primary risk of the change is in thedrip()function ofFeiRewardsDistributoras well as double checking all of the wiring.