pragmasolidity ^0.5.0;/**
* @dev Collection of functions related to the address type,
*/libraryAddress{
/**
* @dev Returns true if `account` is a contract.
*
* This test is non-exhaustive, and there may be false-negatives: during the
* execution of a contract's constructor, its address will be reported as
* not containing a contract.
*
* > It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*/functionisContract(address account) internalviewreturns (bool) {
// This method relies in extcodesize, which returns 0 for contracts in// construction, since the code is only stored at the end of the// constructor execution.uint256 size;
// solhint-disable-next-line no-inline-assemblyassembly { size :=extcodesize(account) }
return size >0;
}
}
Contract Source Code
File 2 of 11: ERC20Detailed.sol
pragmasolidity ^0.5.0;import"./IERC20.sol";
/**
* @dev Optional functions from the ERC20 standard.
*/contractERC20DetailedisIERC20{
stringprivate _name;
stringprivate _symbol;
uint8private _decimals;
/**
* @dev Sets the values for `name`, `symbol`, and `decimals`. All three of
* these values are immutable: they can only be set once during
* construction.
*/constructor (stringmemory name, stringmemory symbol, uint8 decimals) public{
_name = name;
_symbol = symbol;
_decimals = decimals;
}
/**
* @dev Returns the name of the token.
*/functionname() publicviewreturns (stringmemory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/functionsymbol() publicviewreturns (stringmemory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5,05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei.
*
* > Note that this information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* `IERC20.balanceOf` and `IERC20.transfer`.
*/functiondecimals() publicviewreturns (uint8) {
return _decimals;
}
}
Contract Source Code
File 3 of 11: IERC20.sol
pragmasolidity ^0.5.0;/**
* @dev Interface of the ERC20 standard as defined in the EIP. Does not include
* the optional functions; to access them see `ERC20Detailed`.
*/interfaceIERC20{
/**
* @dev Returns the amount of tokens in existence.
*/functiontotalSupply() externalviewreturns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/functionbalanceOf(address account) externalviewreturns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a `Transfer` event.
*/functiontransfer(address recipient, uint256 amount) externalreturns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through `transferFrom`. This is
* zero by default.
*
* This value changes when `approve` or `transferFrom` are called.
*/functionallowance(address owner, address spender) externalviewreturns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* > Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an `Approval` event.
*/functionapprove(address spender, uint256 amount) externalreturns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a `Transfer` event.
*/functiontransferFrom(address sender, address recipient, uint256 amount) externalreturns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/eventTransfer(addressindexedfrom, addressindexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to `approve`. `value` is the new allowance.
*/eventApproval(addressindexed owner, addressindexed spender, uint256 value);
}
pragmasolidity ^0.5.16;// https://docs.synthetix.io/contracts/source/contracts/ownedcontractOwned{
addresspublic owner;
addresspublic nominatedOwner;
constructor(address _owner) public{
require(_owner !=address(0), "Owner address cannot be 0");
owner = _owner;
emit OwnerChanged(address(0), _owner);
}
functionnominateNewOwner(address _owner) externalonlyOwner{
nominatedOwner = _owner;
emit OwnerNominated(_owner);
}
functionacceptOwnership() external{
require(msg.sender== nominatedOwner, "You must be nominated before you can accept ownership");
emit OwnerChanged(owner, nominatedOwner);
owner = nominatedOwner;
nominatedOwner =address(0);
}
modifieronlyOwner{
_onlyOwner();
_;
}
function_onlyOwner() privateview{
require(msg.sender== owner, "Only the contract owner may perform this action");
}
eventOwnerNominated(address newOwner);
eventOwnerChanged(address oldOwner, address newOwner);
}
Contract Source Code
File 6 of 11: Pausable.sol
pragmasolidity ^0.5.16;// Inheritanceimport"./Owned.sol";
// https://docs.synthetix.io/contracts/source/contracts/pausablecontractPausableisOwned{
uintpublic lastPauseTime;
boolpublic paused;
constructor() internal{
// This contract is abstract, and thus cannot be instantiated directlyrequire(owner !=address(0), "Owner must be set");
// Paused will be false, and lastPauseTime will be 0 upon initialisation
}
/**
* @notice Change the paused state of the contract
* @dev Only the contract owner may call this.
*/functionsetPaused(bool _paused) externalonlyOwner{
// Ensure we're actually changing the state before we do anythingif (_paused == paused) {
return;
}
// Set our paused state.
paused = _paused;
// If applicable, set the last pause time.if (paused) {
lastPauseTime =now;
}
// Let everyone know that our pause state has changed.emit PauseChanged(paused);
}
eventPauseChanged(bool isPaused);
modifiernotPaused{
require(!paused, "This action cannot be performed while the contract is paused");
_;
}
}
Contract Source Code
File 7 of 11: ReentrancyGuard.sol
pragmasolidity ^0.5.0;/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the `nonReentrant` modifier
* available, which can be aplied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*/contractReentrancyGuard{
/// @dev counter to allow mutex lock with only one SSTORE operationuint256private _guardCounter;
constructor () internal{
// The counter starts at one to prevent changing it from zero to a non-zero// value, which is a more expensive operation.
_guardCounter =1;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and make it call a
* `private` function that does the actual work.
*/modifiernonReentrant() {
_guardCounter +=1;
uint256 localCounter = _guardCounter;
_;
require(localCounter == _guardCounter, "ReentrancyGuard: reentrant call");
}
}
pragmasolidity ^0.5.0;import"./IERC20.sol";
import"../../math/SafeMath.sol";
import"../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/librarySafeERC20{
usingSafeMathforuint256;
usingAddressforaddress;
functionsafeTransfer(IERC20 token, address to, uint256 value) internal{
callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
functionsafeTransferFrom(IERC20 token, addressfrom, address to, uint256 value) internal{
callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
functionsafeApprove(IERC20 token, address spender, uint256 value) internal{
// safeApprove should only be called when setting an initial allowance,// or when resetting it to zero. To increase and decrease it, use// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'// solhint-disable-next-line max-line-lengthrequire((value ==0) || (token.allowance(address(this), spender) ==0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
functionsafeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal{
uint256 newAllowance = token.allowance(address(this), spender).add(value);
callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
functionsafeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal{
uint256 newAllowance = token.allowance(address(this), spender).sub(value);
callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/functioncallOptionalReturn(IERC20 token, bytesmemory data) private{
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since// we're implementing it ourselves.// A Solidity high level call has three parts:// 1. The target address is checked to verify it contains contract code// 2. The call itself is made, and success asserted// 3. The return value is decoded, which in turn checks the size of the returned data.// solhint-disable-next-line max-line-lengthrequire(address(token).isContract(), "SafeERC20: call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytesmemory returndata) =address(token).call(data);
require(success, "SafeERC20: low-level call failed");
if (returndata.length>0) { // Return data is optional// solhint-disable-next-line max-line-lengthrequire(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
Contract Source Code
File 10 of 11: SafeMath.sol
pragmasolidity ^0.5.0;/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/librarySafeMath{
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
* - Addition cannot overflow.
*/functionadd(uint256 a, uint256 b) internalpurereturns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
* - Subtraction cannot overflow.
*/functionsub(uint256 a, uint256 b) internalpurereturns (uint256) {
require(b <= a, "SafeMath: subtraction overflow");
uint256 c = a - b;
return c;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
* - Multiplication cannot overflow.
*/functionmul(uint256 a, uint256 b) internalpurereturns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the// benefit is lost if 'b' is also tested.// See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522if (a ==0) {
return0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/functiondiv(uint256 a, uint256 b) internalpurereturns (uint256) {
// Solidity only automatically asserts when dividing by 0require(b >0, "SafeMath: division by zero");
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't holdreturn c;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/functionmod(uint256 a, uint256 b) internalpurereturns (uint256) {
require(b !=0, "SafeMath: modulo by zero");
return a % b;
}
}
Contract Source Code
File 11 of 11: StakingRewards.sol
pragmasolidity ^0.5.16;import"../contracts/math/SafeMath.sol";
import"../contracts/token/ERC20/ERC20Detailed.sol";
import"../contracts/token/ERC20/SafeERC20.sol";
import"../contracts/utils/ReentrancyGuard.sol";
// Inheritanceimport"./interfaces/IStakingRewards.sol";
import"./RewardsDistributionRecipient.sol";
import"./Pausable.sol";
// https://docs.synthetix.io/contracts/source/contracts/stakingrewardscontractStakingRewardsisIStakingRewards, RewardsDistributionRecipient, ReentrancyGuard, Pausable{
usingSafeMathforuint256;
usingSafeERC20forIERC20;
/* ========== STATE VARIABLES ========== */
IERC20 public rewardsToken;
IERC20 public stakingToken;
uint256public periodFinish =0;
uint256public rewardRate =0;
uint256public rewardsDuration =7days;
uint256public lastUpdateTime;
uint256public rewardPerTokenStored;
mapping(address=>uint256) public userRewardPerTokenPaid;
mapping(address=>uint256) public rewards;
uint256private _totalSupply;
mapping(address=>uint256) private _balances;
/* ========== CONSTRUCTOR ========== */constructor(address _owner,
address _rewardsDistribution,
address _rewardsToken,
address _stakingToken
) publicOwned(_owner) {
rewardsToken = IERC20(_rewardsToken);
stakingToken = IERC20(_stakingToken);
rewardsDistribution = _rewardsDistribution;
}
/* ========== VIEWS ========== */functiontotalSupply() externalviewreturns (uint256) {
return _totalSupply;
}
functionbalanceOf(address account) externalviewreturns (uint256) {
return _balances[account];
}
functionlastTimeRewardApplicable() publicviewreturns (uint256) {
returnblock.timestamp< periodFinish ? block.timestamp : periodFinish;
}
functionrewardPerToken() publicviewreturns (uint256) {
if (_totalSupply ==0) {
return rewardPerTokenStored;
}
return
rewardPerTokenStored.add(
lastTimeRewardApplicable().sub(lastUpdateTime).mul(rewardRate).mul(1e18).div(_totalSupply)
);
}
functionearned(address account) publicviewreturns (uint256) {
return _balances[account].mul(rewardPerToken().sub(userRewardPerTokenPaid[account])).div(1e18).add(rewards[account]);
}
functiongetRewardForDuration() externalviewreturns (uint256) {
return rewardRate.mul(rewardsDuration);
}
/* ========== MUTATIVE FUNCTIONS ========== */functionstake(uint256 amount) externalnonReentrantnotPausedupdateReward(msg.sender) {
require(amount >0, "Cannot stake 0");
_totalSupply = _totalSupply.add(amount);
_balances[msg.sender] = _balances[msg.sender].add(amount);
stakingToken.safeTransferFrom(msg.sender, address(this), amount);
emit Staked(msg.sender, amount);
}
functionwithdraw(uint256 amount) publicnonReentrantupdateReward(msg.sender) {
require(amount >0, "Cannot withdraw 0");
_totalSupply = _totalSupply.sub(amount);
_balances[msg.sender] = _balances[msg.sender].sub(amount);
stakingToken.safeTransfer(msg.sender, amount);
emit Withdrawn(msg.sender, amount);
}
functiongetReward() publicnonReentrantupdateReward(msg.sender) {
uint256 reward = rewards[msg.sender];
if (reward >0) {
rewards[msg.sender] =0;
rewardsToken.safeTransfer(msg.sender, reward);
emit RewardPaid(msg.sender, reward);
}
}
functionexit() external{
withdraw(_balances[msg.sender]);
getReward();
}
/* ========== RESTRICTED FUNCTIONS ========== */functionnotifyRewardAmount(uint256 reward) externalonlyRewardsDistributionupdateReward(address(0)) {
if (block.timestamp>= periodFinish) {
rewardRate = reward.div(rewardsDuration);
} else {
uint256 remaining = periodFinish.sub(block.timestamp);
uint256 leftover = remaining.mul(rewardRate);
rewardRate = reward.add(leftover).div(rewardsDuration);
}
// 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// very high values of rewardRate in the earned and rewardsPerToken functions;// Reward + leftover must be less than 2^256 / 10^18 to avoid overflow.uint balance = rewardsToken.balanceOf(address(this));
require(rewardRate <= balance.div(rewardsDuration), "Provided reward too high");
lastUpdateTime =block.timestamp;
periodFinish =block.timestamp.add(rewardsDuration);
emit RewardAdded(reward);
}
// Added to support recovering LP Rewards from other systems such as BAL to be distributed to holdersfunctionrecoverERC20(address tokenAddress, uint256 tokenAmount) externalonlyOwner{
require(tokenAddress !=address(stakingToken), "Cannot withdraw the staking token");
IERC20(tokenAddress).safeTransfer(owner, tokenAmount);
emit Recovered(tokenAddress, tokenAmount);
}
functionsetRewardsDuration(uint256 _rewardsDuration) externalonlyOwner{
require(
block.timestamp> periodFinish,
"Previous rewards period must be complete before changing the duration for the new period"
);
rewardsDuration = _rewardsDuration;
emit RewardsDurationUpdated(rewardsDuration);
}
/* ========== MODIFIERS ========== */modifierupdateReward(address account) {
rewardPerTokenStored = rewardPerToken();
lastUpdateTime = lastTimeRewardApplicable();
if (account !=address(0)) {
rewards[account] = earned(account);
userRewardPerTokenPaid[account] = rewardPerTokenStored;
}
_;
}
/* ========== EVENTS ========== */eventRewardAdded(uint256 reward);
eventStaked(addressindexed user, uint256 amount);
eventWithdrawn(addressindexed user, uint256 amount);
eventRewardPaid(addressindexed user, uint256 reward);
eventRewardsDurationUpdated(uint256 newDuration);
eventRecovered(address token, uint256 amount);
}