synthetix_maple_liquidity_mining_diff

Created Diff never expires
102 removals
Lines
Total
Removed
Words
Total
Removed
To continue using this feature, upgrade to
Diffchecker logo
Diffchecker Pro
177 lines
141 additions
Lines
Total
Added
Words
Total
Added
To continue using this feature, upgrade to
Diffchecker logo
Diffchecker Pro
215 lines
pragma solidity ^0.5.16;
// SPDX-License-Identifier: AGPL-3.0-or-later

pragma solidity 0.6.11;
import "openzeppelin-solidity-2.3.0/contracts/math/Math.sol";
import "openzeppelin-solidity-2.3.0/contracts/math/SafeMath.sol";
import "openzeppelin-solidity-2.3.0/contracts/token/ERC20/ERC20Detailed.sol";
import "openzeppelin-solidity-2.3.0/contracts/token/ERC20/SafeERC20.sol";
import "openzeppelin-solidity-2.3.0/contracts/utils/ReentrancyGuard.sol";


// Inheritance
import "lib/openzeppelin-contracts/contracts/access/Ownable.sol";
import "./interfaces/IStakingRewards.sol";
import "lib/openzeppelin-contracts/contracts/math/Math.sol";
import "./RewardsDistributionRecipient.sol";
import "lib/openzeppelin-contracts/contracts/math/SafeMath.sol";
import "./Pausable.sol";
import "lib/openzeppelin-contracts/contracts/token/ERC20/SafeERC20.sol";


import "./interfaces/IERC2258.sol";


// https://docs.synthetix.io/contracts/source/contracts/stakingrewards
// https://docs.synthetix.io/contracts/source/contracts/stakingrewards
contract StakingRewards is IStakingRewards, RewardsDistributionRecipient, ReentrancyGuard, Pausable {
/// @title MplRewards Synthetix farming contract fork for liquidity mining.
using SafeMath for uint256;
contract MplRewards is Ownable {

using SafeMath for uint256;
using SafeERC20 for IERC20;
using SafeERC20 for IERC20;


/* ========== STATE VARIABLES ========== */
IERC20 public immutable rewardsToken;
IERC2258 public immutable stakingToken;


IERC20 public rewardsToken;
uint256 public periodFinish;
IERC20 public stakingToken;
uint256 public rewardRate;
uint256 public periodFinish = 0;
uint256 public rewardsDuration;
uint256 public rewardRate = 0;
uint256 public rewardsDuration = 7 days;
uint256 public lastUpdateTime;
uint256 public lastUpdateTime;
uint256 public rewardPerTokenStored;
uint256 public rewardPerTokenStored;
uint256 public lastPauseTime;
bool public paused;


mapping(address => uint256) public userRewardPerTokenPaid;
mapping(address => uint256) public userRewardPerTokenPaid;
mapping(address => uint256) public rewards;
mapping(address => uint256) public rewards;


uint256 private _totalSupply;
uint256 private _totalSupply;

mapping(address => uint256) private _balances;
mapping(address => uint256) private _balances;


/* ========== CONSTRUCTOR ========== */
event RewardAdded(uint256 reward);
event Staked(address indexed account, uint256 amount);
event Withdrawn(address indexed account, uint256 amount);
event RewardPaid(address indexed account, uint256 reward);
event RewardsDurationUpdated(uint256 newDuration);
event Recovered(address token, uint256 amount);
event PauseChanged(bool isPaused);


constructor(
constructor(address _rewardsToken, address _stakingToken, address _owner) public {
address _owner,
rewardsToken = IERC20(_rewardsToken);
address _rewardsDistribution,
stakingToken = IERC2258(_stakingToken);
address _rewardsToken,
rewardsDuration = 7 days;
address _stakingToken
transferOwnership(_owner);
) public Owned(_owner) {
rewardsToken = IERC20(_rewardsToken);
stakingToken = IERC20(_stakingToken);
rewardsDistribution = _rewardsDistribution;
}
}


/* ========== VIEWS ========== */
function _updateReward(address account) internal {
uint256 _rewardPerTokenStored = rewardPerToken();
rewardPerTokenStored = _rewardPerTokenStored;
lastUpdateTime = lastTimeRewardApplicable();

if (account != address(0)) {
rewards[account] = earned(account);
userRewardPerTokenPaid[account] = _rewardPerTokenStored;
}
}

function _notPaused() internal view {
require(!paused, "R:PAUSED");
}


function totalSupply() external view returns (uint256) {
function totalSupply() external view returns (uint256) {
return _totalSupply;
return _totalSupply;
}
}


function balanceOf(address account) external view returns (uint256) {
function balanceOf(address account) external view returns (uint256) {
return _balances[account];
return _balances[account];
}
}


function lastTimeRewardApplicable() public view returns (uint256) {
function lastTimeRewardApplicable() public view returns (uint256) {
return Math.min(block.timestamp, periodFinish);
return Math.min(block.timestamp, periodFinish);
}
}


function rewardPerToken() public view returns (uint256) {
function rewardPerToken() public view returns (uint256) {
if (_totalSupply == 0) {
return _totalSupply == 0
return rewardPerTokenStored;
? rewardPerTokenStored
}
: rewardPerTokenStored.add(
return
lastTimeRewardApplicable().sub(lastUpdateTime).mul(rewardRate).mul(1e18).div(_totalSupply)
rewardPerTokenStored.add(
);
lastTimeRewardApplicable().sub(lastUpdateTime).mul(rewardRate).mul(1e18).div(_totalSupply)
);
}
}


function earned(address account) public view returns (uint256) {
function earned(address account) public view returns (uint256) {
return _balances[account].mul(rewardPerToken().sub(userRewardPerTokenPaid[account])).div(1e18).add(rewards[account]);
return _balances[account].mul(rewardPerToken().sub(userRewardPerTokenPaid[account])).div(1e18).add(rewards[account]);
}
}


function getRewardForDuration() external view returns (uint256) {
function getRewardForDuration() external view returns (uint256) {
return rewardRate.mul(rewardsDuration);
return rewardRate.mul(rewardsDuration);
}
}


/* ========== MUTATIVE FUNCTIONS ========== */
/**

@dev It emits a `Staked` event.
function stake(uint256 amount) external nonReentrant notPaused updateReward(msg.sender) {
*/
require(amount > 0, "Cannot stake 0");
function stake(uint256 amount) external {
_totalSupply = _totalSupply.add(amount);
_notPaused();
_balances[msg.sender] = _balances[msg.sender].add(amount);
_updateReward(msg.sender);
stakingToken.safeTransferFrom(msg.sender, address(this), amount);
uint256 newBalance = _balances[msg.sender].add(amount);
require(amount > 0, "R:ZERO_STAKE");
require(stakingToken.custodyAllowance(msg.sender, address(this)) >= newBalance, "R:INSUF_CUST_ALLOWANCE");
_totalSupply = _totalSupply.add(amount);
_balances[msg.sender] = newBalance;
emit Staked(msg.sender, amount);
emit Staked(msg.sender, amount);
}
}


function withdraw(uint256 amount) public nonReentrant updateReward(msg.sender) {
/**
require(amount > 0, "Cannot withdraw 0");
@dev It emits a `Withdrawn` event.
*/
function withdraw(uint256 amount) public {
_notPaused();
_updateReward(msg.sender);
require(amount > 0, "R:ZERO_WITHDRAW");
_totalSupply = _totalSupply.sub(amount);
_totalSupply = _totalSupply.sub(amount);
_balances[msg.sender] = _balances[msg.sender].sub(amount);
_balances[msg.sender] = _balances[msg.sender].sub(amount);
stakingToken.safeTransfer(msg.sender, amount);
stakingToken.transferByCustodian(msg.sender, msg.sender, amount);
emit Withdrawn(msg.sender, amount);
emit Withdrawn(msg.sender, amount);
}
}


function getReward() public nonReentrant updateReward(msg.sender) {
/**
@dev It emits a `RewardPaid` event if any rewards are received.
*/
function getReward() public {
_notPaused();
_updateReward(msg.sender);
uint256 reward = rewards[msg.sender];
uint256 reward = rewards[msg.sender];
if (reward > 0) {

rewards[msg.sender] = 0;
if (reward == uint256(0)) return;
rewardsToken.safeTransfer(msg.sender, reward);

emit RewardPaid(msg.sender, reward);
rewards[msg.sender] = uint256(0);
}
rewardsToken.safeTransfer(msg.sender, reward);
emit RewardPaid(msg.sender, reward);
}
}


function exit() external {
function exit() external {
withdraw(_balances[msg.sender]);
withdraw(_balances[msg.sender]);
getReward();
getReward();
}
}


/* ========== RESTRICTED FUNCTIONS ========== */
/**
@dev Only the contract Owner may call this.
@dev It emits a `RewardAdded` event.
*/
function notifyRewardAmount(uint256 reward) external onlyOwner {
_updateReward(address(0));


function notifyRewardAmount(uint256 reward) external onlyRewardsDistribution updateReward(address(0)) {
uint256 _rewardRate = block.timestamp >= periodFinish
if (block.timestamp >= periodFinish) {
? reward.div(rewardsDuration)
rewardRate = reward.div(rewardsDuration);
: reward.add(
} else {
periodFinish.sub(block.timestamp).mul(rewardRate)
uint256 remaining = periodFinish.sub(block.timestamp);
).div(rewardsDuration);
uint256 leftover = remaining.mul(rewardRate);

rewardRate = reward.add(leftover).div(rewardsDuration);
rewardRate = _rewardRate;
}


// Ensure the provided reward amount is not more than the balance in the contract.
// Ensure the provided reward amount is not more than the balance in the contract.
// This keeps the reward rate in the right range, preventing overflows due to
// This keeps the reward rate in the right range, preventing overflows due to
// very high values of rewardRate in the earned and rewardsPerToken functions;
// very high values of rewardRate in the earned and rewardsPerToken functions;
// Reward + leftover must be less than 2^256 / 10^18 to avoid overflow.
// Reward + leftover must be less than 2^256 / 10^18 to avoid overflow.
uint balance = rewardsToken.balanceOf(address(this));
uint256 balance = rewardsToken.balanceOf(address(this));
require(rewardRate <= balance.div(rewardsDuration), "Provided reward too high");
require(_rewardRate <= balance.div(rewardsDuration), "R:REWARD_TOO_HIGH");


lastUpdateTime = block.timestamp;
lastUpdateTime = block.timestamp;
periodFinish = block.timestamp.add(rewardsDuration);
periodFinish = block.timestamp.add(rewardsDuration);
emit RewardAdded(reward);
emit RewardAdded(reward);
}
}


// End rewards emission earlier
/**
function updatePeriodFinish(uint timestamp) external onlyOwner updateReward(address(0)) {
@dev End rewards emission earlier. Only the contract Owner may call this.
*/
function updatePeriodFinish(uint256 timestamp) external onlyOwner {
_updateReward(address(0));
periodFinish = timestamp;
periodFinish = timestamp;
}
}


// Added to support recovering LP Rewards from other systems such as BAL to be distributed to holders
/**
@dev Added to support recovering tokens unintentionally sent to this contract.
Only the contract Owner may call this.
@dev It emits a `Recovered` event.
*/
function recoverERC20(address tokenAddress, uint256 tokenAmount) external onlyOwner {
function recoverERC20(address tokenAddress, uint256 tokenAmount) external onlyOwner {
require(tokenAddress != address(stakingToken), "Cannot withdraw the staking token");
IERC20(tokenAddress).safeTransfer(owner(), tokenAmount);
IERC20(tokenAddress).safeTransfer(owner, tokenAmount);
emit Recovered(tokenAddress, tokenAmount);
emit Recovered(tokenAddress, tokenAmount);
}
}


/**
@dev Only the contract Owner may call this.
@dev It emits a `RewardsDurationUpdated` event.
*/
function setRewardsDuration(uint256 _rewardsDuration) external onlyOwner {
function setRewardsDuration(uint256 _rewardsDuration) external onlyOwner {
require(
require(block.timestamp > periodFinish, "R:PERIOD_NOT_FINISHED");
block.timestamp > periodFinish,
"Previous rewards period must be complete before changing the duration for the new period"
);
rewardsDuration = _rewardsDuration;
rewardsDuration = _rewardsDuration;
emit RewardsDurationUpdated(rewardsDuration);
emit RewardsDurationUpdated(rewardsDuration);
}
}


/* ========== MODIFIERS ========== */
/**
@dev Change the paused state of the contract. Only the contract Owner may call this.
@dev It emits a `PauseChanged` event.
*/
function setPaused(bool _paused) external onlyOwner {
// Ensure we're actually changing the state before we do anything
require(_paused != paused, "R:ALREADY_SET");


modifier updateReward(address account) {
// Set our paused state.
rewardPerTokenStored = rewardPerToken();
paused = _paused;
lastUpdateTime = lastTimeRewardApplicable();

if (account != address(0)) {
// If applicable, set the last pause time.
rewards[account] = earned(account);
if (_paused) lastPauseTime = block.timestamp;
userRewardPerTokenPaid[account] = rewardPerTokenStored;

}
// Let everyone know that our pause state has changed.
_;
emit PauseChanged(paused);
}
}


/* ========== EVENTS ========== */

event RewardAdded(uint256 reward);
event Staked(address indexed user, uint256 amount);
event Withdrawn(address indexed user, uint256 amount);
event RewardPaid(address indexed user, uint256 reward);
event RewardsDurationUpdated(uint256 newDuration);
event Recovered(address token, uint256 amount);
}
}
{"mode":"full","isActive":false}