Staking Reward Factory Contact
FeSwap staking reward factory contact is used to distribute reward FESW tokens to the staking reward contracts.
Staking Reward Contract Address #
ETH NetWork | Staking Reward Factory Contract Address |
---|---|
ETH Mainnet | 0x9f35C6E6bb19A4cd7b1527CbCEB7d70be1021675 |
ETH Testnet Ropsten | 0x940EA0910C2B71794e7Bc411ea6cf45091B1d1C4 |
ETH Testnet Rinkeby | 0x940EA0910C2B71794e7Bc411ea6cf45091B1d1C4 |
ETH Testnet Goerli | 0x940EA0910C2B71794e7Bc411ea6cf45091B1d1C4 |
ETH Testnet Kovan | 0x940EA0910C2B71794e7Bc411ea6cf45091B1d1C4 |
Staking Reward Contract Code #
The open-source FeSwap StakingTwinRewardsFactory
contact is stored at Github Governance Project
Following is the code deployed:
StakingTwinRewardsFactory.sol
// SPDX-License-Identifier: GPL-3.0pragma solidity ^0.7.0;
import '@openzeppelin/contracts/access/Ownable.sol';import "./StakingTwinRewards.sol";
interface IFeSwapPair { function tokenIn() external view returns (address); function tokenOut() external view returns (address);}
contract StakingTwinRewardsFactory is Ownable { // immutables address public rewardsToken; uint public stakingRewardsGenesis;
// the staking tokens for which the rewards contract has been deployed address[] public stakingTokens;
// info about rewards for a particular staking token struct StakingRewardsInfo { address stakingTwinToken; address stakingRewards; uint rewardAmount; uint rewardsDuration; }
// rewards info by staking token mapping(address => StakingRewardsInfo) public stakingRewardsInfoByStakingToken;
constructor( address _rewardsToken, uint _stakingRewardsGenesis ) Ownable() { require(_stakingRewardsGenesis >= block.timestamp, 'StakingRewardsFactory::constructor: genesis too soon');
rewardsToken = _rewardsToken; stakingRewardsGenesis = _stakingRewardsGenesis; }
///// permissioned functions
// deploy a staking reward contract for the staking token, and store the reward amount // the reward will be distributed to the staking reward contract no sooner than the genesis function deploy(address stakingTokenA, address stakingTokenB, uint rewardAmount, uint rewardsDuration) public onlyOwner { require(stakingTokenA < stakingTokenB, "Wrong token order"); StakingRewardsInfo storage info = stakingRewardsInfoByStakingToken[stakingTokenA]; if(info.stakingRewards == address(0)) { require(IFeSwapPair(stakingTokenA).tokenIn() == IFeSwapPair(stakingTokenB).tokenOut(), "Wrong pair token"); require(IFeSwapPair(stakingTokenA).tokenOut() == IFeSwapPair(stakingTokenB).tokenIn(), "Wrong pair token");
info.stakingRewards = address(new StakingTwinRewards(/*_rewardsDistribution=*/ address(this), rewardsToken, stakingTokenA, stakingTokenB)); info.stakingTwinToken = stakingTokenB; info.rewardAmount = rewardAmount; info.rewardsDuration = rewardsDuration; stakingTokens.push(stakingTokenA); } else { require(info.rewardAmount == 0, 'StakingRewardsFactory::deploy: already deployed'); require(stakingTokenB == info.stakingTwinToken, "Wrong twin token"); info.rewardAmount = rewardAmount; // refill the reward contract info.rewardsDuration = rewardsDuration; }
}
///// permissionless functions
// call notifyRewardAmount for all staking tokens. function notifyRewardAmounts() public { require(stakingTokens.length > 0, 'StakingRewardsFactory::notifyRewardAmounts: called before any deploys'); for (uint i = 0; i < stakingTokens.length; i++) { notifyRewardAmount(stakingTokens[i]); } }
// notify reward amount for an individual staking token. // this is a fallback in case the notifyRewardAmounts costs too much gas to call for all contracts function notifyRewardAmount(address stakingToken) public { require(block.timestamp >= stakingRewardsGenesis, 'StakingRewardsFactory::notifyRewardAmount: not ready');
StakingRewardsInfo storage info = stakingRewardsInfoByStakingToken[stakingToken]; require(info.stakingRewards != address(0), 'StakingRewardsFactory::notifyRewardAmount: not deployed');
if (info.rewardAmount > 0) { uint rewardAmount = info.rewardAmount; info.rewardAmount = 0;
require( IERC20(rewardsToken).transfer(info.stakingRewards, rewardAmount), 'StakingRewardsFactory::notifyRewardAmount: transfer failed' ); StakingTwinRewards(info.stakingRewards).notifyRewardAmount(rewardAmount, info.rewardsDuration); } }}