文件 1 的 3:IERC20.sol
pragma solidity >=0.6.0 <0.8.0;
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
文件 2 的 3:SafeMath.sol
pragma solidity >=0.6.0 <0.8.0;
library SafeMath {
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow");
}
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
uint256 c = a / b;
return c;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return mod(a, b, "SafeMath: modulo by zero");
}
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
}
文件 3 的 3:YieldFarmLP.sol
pragma solidity ^0.7.6;
import "./SafeMath.sol";
import "./IERC20.sol";
interface IStaking {
function getEpochId(uint timestamp) external view returns (uint);
function getEpochUserBalance(address user, address token, uint128 epoch) external view returns(uint);
function getEpochPoolSize(address token, uint128 epoch) external view returns (uint);
function epoch1Start() external view returns (uint);
function epochDuration() external view returns (uint);
function hasReferrer(address addr) external view returns(bool);
function referrals(address addr) external view returns(address);
function firstReferrerRewardPercentage() external view returns(uint256);
function secondReferrerRewardPercentage() external view returns(uint256);
}
interface TokenInterface is IERC20 {
function mintSupply(address _investorAddress, uint256 _amount) external;
}
contract YieldFarmLP {
using SafeMath for uint;
using SafeMath for uint128;
uint public constant NR_OF_EPOCHS = 24;
address public _uniLP;
address public _owner;
TokenInterface private _swapp;
IStaking private _staking;
uint[] private epochs = new uint[](NR_OF_EPOCHS + 1);
uint128 public lastInitializedEpoch;
mapping(address => uint128) private lastEpochIdHarvested;
uint public epochDuration;
uint public epochStart;
mapping(uint128 => uint256) public epochAmounts;
event MassHarvest(address indexed user, uint256 epochsHarvested, uint256 totalValue);
event Harvest(address indexed user, uint128 indexed epochId, uint256 amount);
event ReferrerRewardCollected(address indexed staker, address indexed referrer, uint256 rewardAmount);
event Referrer2RewardCollected(address indexed staker, address indexed referrer, address indexed referrer2, uint256 rewardAmount);
constructor() {
_swapp = TokenInterface(0x8CB924583681cbFE487A62140a994A49F833c244);
_staking = IStaking(0x245a551ee0F55005e510B239c917fA34b41B3461);
epochDuration = _staking.epochDuration();
epochStart = _staking.epoch1Start();
_owner = msg.sender;
}
function setEpochAmount(uint128 epochId, uint256 amount) external {
require(msg.sender == _owner, "Only owner can update epoch amount");
require(epochId > 0 && epochId <= NR_OF_EPOCHS, "Minimum epoch number is 1 and Maximum number of epochs is 24");
require(epochId > _getEpochId(), "Only future epoch can be updated");
epochAmounts[epochId] = amount;
}
function getTotalAmountPerEpoch() public view returns (uint) {
uint128 currentEpoch = _getEpochId();
if (currentEpoch > NR_OF_EPOCHS) {
currentEpoch = 25;
}
return epochAmounts[currentEpoch-1].mul(10**18);
}
function getCurrentEpochAmount() public view returns (uint) {
uint128 currentEpoch = _getEpochId();
if (currentEpoch <= 0 || currentEpoch > NR_OF_EPOCHS) {
return 0;
}
return epochAmounts[currentEpoch];
}
function getTotalDistributedAmount() external view returns(uint256) {
uint256 totalDistributed;
for (uint128 i = 1; i <= NR_OF_EPOCHS; i++) {
totalDistributed += epochAmounts[i];
}
return totalDistributed;
}
function setLPAddress(address lp) external {
if (_uniLP == address(0)) {
_uniLP = lp;
}
}
function massHarvest() external returns (uint){
uint totalDistributedValue;
uint epochId = _getEpochId().sub(1);
if (epochId > NR_OF_EPOCHS) {
epochId = NR_OF_EPOCHS;
}
for (uint128 i = lastEpochIdHarvested[msg.sender] + 1; i <= epochId; i++) {
totalDistributedValue += _harvest(i);
}
emit MassHarvest(msg.sender, epochId - lastEpochIdHarvested[msg.sender], totalDistributedValue);
if (totalDistributedValue > 0) {
_swapp.mintSupply(msg.sender, totalDistributedValue);
distributeReferrerReward(totalDistributedValue);
}
return totalDistributedValue;
}
function harvest (uint128 epochId) external returns (uint){
require (_getEpochId() > epochId, "This epoch is in the future");
require(epochId <= NR_OF_EPOCHS, "Maximum number of epochs is 24");
require (lastEpochIdHarvested[msg.sender].add(1) == epochId, "Harvest in order");
uint userReward = _harvest(epochId);
if (userReward > 0) {
_swapp.mintSupply(msg.sender, userReward);
distributeReferrerReward(userReward);
}
emit Harvest(msg.sender, epochId, userReward);
return userReward;
}
function distributeReferrerReward(uint256 stakerReward) internal {
if (_staking.hasReferrer(msg.sender)) {
address referrer = _staking.referrals(msg.sender);
uint256 ref1Reward = stakerReward.mul(_staking.firstReferrerRewardPercentage()).div(10000);
_swapp.mintSupply(referrer, ref1Reward);
emit ReferrerRewardCollected(msg.sender, referrer, ref1Reward);
if (_staking.hasReferrer(referrer)) {
address referrer2 = _staking.referrals(referrer);
uint256 ref2Reward = stakerReward.mul(_staking.secondReferrerRewardPercentage()).div(10000);
_swapp.mintSupply(referrer2, ref2Reward);
emit Referrer2RewardCollected(msg.sender, referrer, referrer2, ref2Reward);
}
}
}
function getPoolSize(uint128 epochId) external view returns (uint) {
return _getPoolSize(epochId);
}
function getCurrentEpoch() external view returns (uint) {
return _getEpochId();
}
function getEpochStake(address userAddress, uint128 epochId) external view returns (uint) {
return _getUserBalancePerEpoch(userAddress, epochId);
}
function userLastEpochIdHarvested() external view returns (uint){
return lastEpochIdHarvested[msg.sender];
}
function _initEpoch(uint128 epochId) internal {
require(lastInitializedEpoch.add(1) == epochId, "Epoch can be init only in order");
lastInitializedEpoch = epochId;
epochs[epochId] = _getPoolSize(epochId);
}
function _harvest (uint128 epochId) internal returns (uint) {
if (lastInitializedEpoch < epochId) {
_initEpoch(epochId);
}
lastEpochIdHarvested[msg.sender] = epochId;
if (epochs[epochId] == 0) {
return 0;
}
return getTotalAmountPerEpoch()
.mul(_getUserBalancePerEpoch(msg.sender, epochId))
.div(epochs[epochId]);
}
function _getPoolSize(uint128 epochId) internal view returns (uint) {
return _staking.getEpochPoolSize(_uniLP, epochId);
}
function _getUserBalancePerEpoch(address userAddress, uint128 epochId) internal view returns (uint){
return _staking.getEpochUserBalance(userAddress, _uniLP, epochId);
}
function _getEpochId() internal view returns (uint128 epochId) {
if (block.timestamp < epochStart) {
return 0;
}
epochId = uint128(block.timestamp.sub(epochStart).div(epochDuration).add(1));
}
}
{
"compilationTarget": {
"YieldFarmLP.sol": "YieldFarmLP"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint128","name":"epochId","type":"uint128"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Harvest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"epochsHarvested","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalValue","type":"uint256"}],"name":"MassHarvest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":true,"internalType":"address","name":"referrer","type":"address"},{"indexed":true,"internalType":"address","name":"referrer2","type":"address"},{"indexed":false,"internalType":"uint256","name":"rewardAmount","type":"uint256"}],"name":"Referrer2RewardCollected","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":true,"internalType":"address","name":"referrer","type":"address"},{"indexed":false,"internalType":"uint256","name":"rewardAmount","type":"uint256"}],"name":"ReferrerRewardCollected","type":"event"},{"inputs":[],"name":"NR_OF_EPOCHS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_uniLP","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint128","name":"","type":"uint128"}],"name":"epochAmounts","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"epochDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"epochStart","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentEpoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentEpochAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"userAddress","type":"address"},{"internalType":"uint128","name":"epochId","type":"uint128"}],"name":"getEpochStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint128","name":"epochId","type":"uint128"}],"name":"getPoolSize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalAmountPerEpoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalDistributedAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint128","name":"epochId","type":"uint128"}],"name":"harvest","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lastInitializedEpoch","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"massHarvest","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"epochId","type":"uint128"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"setEpochAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"lp","type":"address"}],"name":"setLPAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"userLastEpochIdHarvested","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]