文件 1 的 13:Address.sol
pragma solidity >=0.6.11 <0.9.0;
library Address {
function isContract(address account) internal view returns (bool) {
uint256 size;
assembly { size := extcodesize(account) }
return size > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{ value: amount }("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{ value: value }(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
文件 2 的 13:CommunalFarm.sol
pragma solidity >=0.6.11;
pragma experimental ABIEncoderV2;
import "./Math.sol";
import "./SafeMath.sol";
import "./ERC20.sol";
import "./SafeERC20.sol";
import './TransferHelper.sol';
import "./ISaddleD4_LP.sol";
import "./ReentrancyGuard.sol";
import "./Owned.sol";
contract CommunalFarm is Owned, ReentrancyGuard {
using SafeMath for uint256;
using SafeERC20 for ERC20;
ISaddleD4_LP private stakingToken;
uint256 private constant MULTIPLIER_PRECISION = 1e18;
uint256 public periodFinish;
uint256 public lastUpdateTime;
uint256 public lock_max_multiplier = uint256(3e18);
uint256 public lock_time_for_max_multiplier = 1 * 365 * 86400;
uint256 public lock_time_min = 86400;
mapping(address => address) public rewardManagers;
address[] public rewardTokens;
uint256[] public rewardRates;
string[] public rewardSymbols;
mapping(address => uint256) public rewardTokenAddrToIdx;
uint256 public rewardsDuration = 604800;
uint256[] private rewardsPerTokenStored;
mapping(address => mapping(uint256 => uint256)) private userRewardsPerTokenPaid;
mapping(address => mapping(uint256 => uint256)) private rewards;
mapping(address => uint256) private lastRewardClaimTime;
uint256 private _total_liquidity_locked;
uint256 private _total_combined_weight;
mapping(address => uint256) private _locked_liquidity;
mapping(address => uint256) private _combined_weights;
mapping(address => LockedStake[]) private lockedStakes;
mapping(address => bool) public greylist;
bool public stakesUnlocked;
bool public withdrawalsPaused;
bool public rewardsCollectionPaused;
bool public stakingPaused;
struct LockedStake {
bytes32 kek_id;
uint256 start_timestamp;
uint256 liquidity;
uint256 ending_timestamp;
uint256 lock_multiplier;
}
modifier onlyByOwner() {
require(msg.sender == owner, "You are not the owner");
_;
}
modifier onlyTokenManagers(address reward_token_address) {
require(msg.sender == owner || isTokenManagerFor(msg.sender, reward_token_address), "You are not the owner or the correct token manager");
_;
}
modifier notStakingPaused() {
require(stakingPaused == false, "Staking is paused");
_;
}
modifier updateRewardAndBalance(address account, bool sync_too) {
_updateRewardAndBalance(account, sync_too);
_;
}
constructor(
address _owner,
address _stakingToken,
string[] memory _rewardSymbols,
address[] memory _rewardTokens,
address[] memory _rewardManagers,
uint256[] memory _rewardRates
) Owned(_owner){
stakingToken = ISaddleD4_LP(_stakingToken);
rewardTokens = _rewardTokens;
rewardRates = _rewardRates;
rewardSymbols = _rewardSymbols;
lastUpdateTime = block.timestamp;
for (uint256 i = 0; i < _rewardTokens.length; i++){
rewardTokenAddrToIdx[_rewardTokens[i]] = i;
rewardsPerTokenStored.push(0);
rewardManagers[_rewardTokens[i]] = _rewardManagers[i];
}
stakesUnlocked = false;
}
function totalLiquidityLocked() external view returns (uint256) {
return _total_liquidity_locked;
}
function lockedLiquidityOf(address account) external view returns (uint256) {
return _locked_liquidity[account];
}
function totalCombinedWeight() external view returns (uint256) {
return _total_combined_weight;
}
function combinedWeightOf(address account) external view returns (uint256) {
return _combined_weights[account];
}
function calcCurCombinedWeight(address account) public view
returns (
uint256 old_combined_weight,
uint256 new_combined_weight
)
{
old_combined_weight = _combined_weights[account];
new_combined_weight = 0;
for (uint256 i = 0; i < lockedStakes[account].length; i++) {
LockedStake memory thisStake = lockedStakes[account][i];
uint256 lock_multiplier = thisStake.lock_multiplier;
if (thisStake.ending_timestamp <= block.timestamp) {
if (lastRewardClaimTime[account] < thisStake.ending_timestamp){
uint256 time_before_expiry = (thisStake.ending_timestamp).sub(lastRewardClaimTime[account]);
uint256 time_after_expiry = (block.timestamp).sub(thisStake.ending_timestamp);
uint256 numerator = ((lock_multiplier).mul(time_before_expiry)).add(((MULTIPLIER_PRECISION).mul(time_after_expiry)));
lock_multiplier = numerator.div(time_before_expiry.add(time_after_expiry));
}
else {
lock_multiplier = MULTIPLIER_PRECISION;
}
}
uint256 liquidity = thisStake.liquidity;
uint256 combined_boosted_amount = liquidity.mul(lock_multiplier).div(MULTIPLIER_PRECISION);
new_combined_weight = new_combined_weight.add(combined_boosted_amount);
}
}
function lockedStakesOf(address account) external view returns (LockedStake[] memory) {
return lockedStakes[account];
}
function getRewardSymbols() external view returns (string[] memory) {
return rewardSymbols;
}
function getAllRewardTokens() external view returns (address[] memory) {
return rewardTokens;
}
function lockMultiplier(uint256 secs) public view returns (uint256) {
uint256 lock_multiplier =
uint256(MULTIPLIER_PRECISION).add(
secs
.mul(lock_max_multiplier.sub(MULTIPLIER_PRECISION))
.div(lock_time_for_max_multiplier)
);
if (lock_multiplier > lock_max_multiplier) lock_multiplier = lock_max_multiplier;
return lock_multiplier;
}
function lastTimeRewardApplicable() internal view returns (uint256) {
return Math.min(block.timestamp, periodFinish);
}
function rewardsPerToken() public view returns (uint256[] memory newRewardsPerTokenStored) {
if (_total_liquidity_locked == 0 || _total_combined_weight == 0) {
return rewardsPerTokenStored;
}
else {
newRewardsPerTokenStored = new uint256[](rewardTokens.length);
for (uint256 i = 0; i < rewardsPerTokenStored.length; i++){
newRewardsPerTokenStored[i] = rewardsPerTokenStored[i].add(
lastTimeRewardApplicable().sub(lastUpdateTime).mul(rewardRates[i]).mul(1e18).div(_total_combined_weight)
);
}
return newRewardsPerTokenStored;
}
}
function earned(address account) public view returns (uint256[] memory new_earned) {
uint256[] memory reward_arr = rewardsPerToken();
new_earned = new uint256[](rewardTokens.length);
if (_combined_weights[account] == 0){
for (uint256 i = 0; i < rewardTokens.length; i++){
new_earned[i] = 0;
}
}
else {
for (uint256 i = 0; i < rewardTokens.length; i++){
new_earned[i] = (_combined_weights[account])
.mul(reward_arr[i].sub(userRewardsPerTokenPaid[account][i]))
.div(1e18)
.add(rewards[account][i]);
}
}
}
function getRewardForDuration() external view returns (uint256[] memory rewards_per_duration_arr) {
rewards_per_duration_arr = new uint256[](rewardRates.length);
for (uint256 i = 0; i < rewardRates.length; i++){
rewards_per_duration_arr[i] = rewardRates[i].mul(rewardsDuration);
}
}
function isTokenManagerFor(address caller_addr, address reward_token_addr) public view returns (bool){
if (caller_addr == owner) return true;
else if (rewardManagers[reward_token_addr] == caller_addr) return true;
return false;
}
function _updateRewardAndBalance(address account, bool sync_too) internal {
if (sync_too){
sync();
}
if (account != address(0)) {
(
uint256 old_combined_weight,
uint256 new_combined_weight
) = calcCurCombinedWeight(account);
_syncEarned(account);
if (new_combined_weight >= old_combined_weight) {
uint256 weight_diff = new_combined_weight.sub(old_combined_weight);
_total_combined_weight = _total_combined_weight.add(weight_diff);
_combined_weights[account] = old_combined_weight.add(weight_diff);
} else {
uint256 weight_diff = old_combined_weight.sub(new_combined_weight);
_total_combined_weight = _total_combined_weight.sub(weight_diff);
_combined_weights[account] = old_combined_weight.sub(weight_diff);
}
}
}
function _syncEarned(address account) internal {
if (account != address(0)) {
uint256[] memory earned_arr = earned(account);
for (uint256 i = 0; i < earned_arr.length; i++){
rewards[account][i] = earned_arr[i];
}
for (uint256 i = 0; i < earned_arr.length; i++){
userRewardsPerTokenPaid[account][i] = rewardsPerTokenStored[i];
}
}
}
function stakeLocked(uint256 liquidity, uint256 secs) nonReentrant public {
_stakeLocked(msg.sender, msg.sender, liquidity, secs, block.timestamp);
}
function _stakeLocked(
address staker_address,
address source_address,
uint256 liquidity,
uint256 secs,
uint256 start_timestamp
) internal updateRewardAndBalance(staker_address, true) {
require(!stakingPaused, "Staking is paused");
require(liquidity > 0, "Must stake more than zero");
require(greylist[staker_address] == false, "Address has been greylisted");
require(secs >= lock_time_min, "Minimum stake time not met");
require(secs <= lock_time_for_max_multiplier,"Trying to lock for too long");
uint256 lock_multiplier = lockMultiplier(secs);
bytes32 kek_id = keccak256(abi.encodePacked(staker_address, start_timestamp, liquidity, _locked_liquidity[staker_address]));
lockedStakes[staker_address].push(LockedStake(
kek_id,
start_timestamp,
liquidity,
start_timestamp.add(secs),
lock_multiplier
));
TransferHelper.safeTransferFrom(address(stakingToken), source_address, address(this), liquidity);
_total_liquidity_locked = _total_liquidity_locked.add(liquidity);
_locked_liquidity[staker_address] = _locked_liquidity[staker_address].add(liquidity);
_updateRewardAndBalance(staker_address, false);
if (lastRewardClaimTime[staker_address] == 0) lastRewardClaimTime[staker_address] = block.timestamp;
emit StakeLocked(staker_address, liquidity, secs, kek_id, source_address);
}
function withdrawLocked(bytes32 kek_id) nonReentrant public {
require(withdrawalsPaused == false, "Withdrawals paused");
_withdrawLocked(msg.sender, msg.sender, kek_id);
}
function _withdrawLocked(address staker_address, address destination_address, bytes32 kek_id) internal {
_getReward(staker_address, destination_address);
LockedStake memory thisStake;
thisStake.liquidity = 0;
uint theArrayIndex;
for (uint256 i = 0; i < lockedStakes[staker_address].length; i++){
if (kek_id == lockedStakes[staker_address][i].kek_id){
thisStake = lockedStakes[staker_address][i];
theArrayIndex = i;
break;
}
}
require(thisStake.kek_id == kek_id, "Stake not found");
require(block.timestamp >= thisStake.ending_timestamp || stakesUnlocked == true, "Stake is still locked!");
uint256 liquidity = thisStake.liquidity;
if (liquidity > 0) {
_total_liquidity_locked = _total_liquidity_locked.sub(liquidity);
_locked_liquidity[staker_address] = _locked_liquidity[staker_address].sub(liquidity);
delete lockedStakes[staker_address][theArrayIndex];
_updateRewardAndBalance(staker_address, false);
stakingToken.transfer(destination_address, liquidity);
emit WithdrawLocked(staker_address, liquidity, kek_id, destination_address);
}
}
function getReward() external nonReentrant returns (uint256[] memory) {
require(rewardsCollectionPaused == false,"Rewards collection paused");
return _getReward(msg.sender, msg.sender);
}
function _getReward(address rewardee, address destination_address) internal updateRewardAndBalance(rewardee, true) returns (uint256[] memory rewards_before) {
rewards_before = new uint256[](rewardTokens.length);
for (uint256 i = 0; i < rewardTokens.length; i++){
rewards_before[i] = rewards[rewardee][i];
rewards[rewardee][i] = 0;
ERC20(rewardTokens[i]).transfer(destination_address, rewards_before[i]);
emit RewardPaid(rewardee, rewards_before[i], rewardTokens[i], destination_address);
}
lastRewardClaimTime[rewardee] = block.timestamp;
}
function retroCatchUp() internal {
require(block.timestamp > periodFinish, "Period has not expired yet!");
uint256 num_periods_elapsed = uint256(block.timestamp.sub(periodFinish)) / rewardsDuration;
for (uint256 i = 0; i < rewardTokens.length; i++){
require(rewardRates[i].mul(rewardsDuration).mul(num_periods_elapsed + 1) <= ERC20(rewardTokens[i]).balanceOf(address(this)), string(abi.encodePacked("Not enough reward tokens available: ", rewardTokens[i])) );
}
periodFinish = periodFinish.add((num_periods_elapsed.add(1)).mul(rewardsDuration));
_updateStoredRewardsAndTime();
emit RewardsPeriodRenewed(address(stakingToken));
}
function _updateStoredRewardsAndTime() internal {
uint256[] memory rewards_per_token = rewardsPerToken();
for (uint256 i = 0; i < rewardsPerTokenStored.length; i++){
rewardsPerTokenStored[i] = rewards_per_token[i];
}
lastUpdateTime = lastTimeRewardApplicable();
}
function sync() public {
if (block.timestamp > periodFinish) {
retroCatchUp();
}
else {
_updateStoredRewardsAndTime();
}
}
function recoverERC20(address tokenAddress, uint256 tokenAmount) external onlyTokenManagers(tokenAddress) {
require(tokenAddress != address(stakingToken), "Cannot rug staking / LP tokens");
bool isRewardToken = false;
for (uint256 i = 0; i < rewardTokens.length; i++){
if (rewardTokens[i] == tokenAddress) {
isRewardToken = true;
break;
}
}
if (isRewardToken && rewardManagers[tokenAddress] == msg.sender){
ERC20(tokenAddress).transfer(msg.sender, tokenAmount);
emit Recovered(msg.sender, tokenAddress, tokenAmount);
return;
}
else if (!isRewardToken && (msg.sender == owner)){
ERC20(tokenAddress).transfer(msg.sender, tokenAmount);
emit Recovered(msg.sender, tokenAddress, tokenAmount);
return;
}
else {
revert("No valid tokens to recover");
}
}
function setRewardsDuration(uint256 _rewardsDuration) external onlyByOwner {
require(_rewardsDuration >= 86400, "Rewards duration must be at least one day");
require(
periodFinish == 0 || block.timestamp > periodFinish,
"Reward period incomplete"
);
rewardsDuration = _rewardsDuration;
emit RewardsDurationUpdated(rewardsDuration);
}
function setMultipliers(uint256 _lock_max_multiplier) external onlyByOwner {
require(_lock_max_multiplier >= uint256(1e18), "Multiplier must be greater than or equal to 1e18");
lock_max_multiplier = _lock_max_multiplier;
emit LockedStakeMaxMultiplierUpdated(lock_max_multiplier);
}
function setLockedStakeTimeForMinAndMaxMultiplier(uint256 _lock_time_for_max_multiplier, uint256 _lock_time_min) external onlyByOwner {
require(_lock_time_for_max_multiplier >= 1, "Mul max time must be >= 1");
require(_lock_time_min >= 1, "Mul min time must be >= 1");
lock_time_for_max_multiplier = _lock_time_for_max_multiplier;
lock_time_min = _lock_time_min;
emit LockedStakeTimeForMaxMultiplier(lock_time_for_max_multiplier);
emit LockedStakeMinTime(_lock_time_min);
}
function initializeDefault() external onlyByOwner {
lastUpdateTime = block.timestamp;
periodFinish = block.timestamp.add(rewardsDuration);
emit DefaultInitialization();
}
function greylistAddress(address _address) external onlyByOwner {
greylist[_address] = !(greylist[_address]);
}
function unlockStakes() external onlyByOwner {
stakesUnlocked = !stakesUnlocked;
}
function toggleStaking() external onlyByOwner {
stakingPaused = !stakingPaused;
}
function toggleWithdrawals() external onlyByOwner {
withdrawalsPaused = !withdrawalsPaused;
}
function toggleRewardsCollection() external onlyByOwner {
rewardsCollectionPaused = !rewardsCollectionPaused;
}
function setRewardRate(address reward_token_address, uint256 new_rate, bool sync_too) external onlyTokenManagers(reward_token_address) {
rewardRates[rewardTokenAddrToIdx[reward_token_address]] = new_rate;
if (sync_too){
sync();
}
}
function changeTokenManager(address reward_token_address, address new_manager_address) external onlyTokenManagers(reward_token_address) {
rewardManagers[reward_token_address] = new_manager_address;
}
event StakeLocked(address indexed user, uint256 amount, uint256 secs, bytes32 kek_id, address source_address);
event WithdrawLocked(address indexed user, uint256 amount, bytes32 kek_id, address destination_address);
event RewardPaid(address indexed user, uint256 reward, address token_address, address destination_address);
event RewardsDurationUpdated(uint256 newDuration);
event Recovered(address destination_address, address token, uint256 amount);
event RewardsPeriodRenewed(address token);
event DefaultInitialization();
event LockedStakeMaxMultiplierUpdated(uint256 multiplier);
event LockedStakeTimeForMaxMultiplier(uint256 secs);
event LockedStakeMinTime(uint256 secs);
}
文件 3 的 13:CommunalFarm_SaddleD4.sol
pragma solidity >=0.6.11;
pragma experimental ABIEncoderV2;
import "./CommunalFarm.sol";
contract CommunalFarm_SaddleD4 is CommunalFarm {
constructor(
address _owner,
address _stakingToken,
string[] memory _rewardSymbols,
address[] memory _rewardTokens,
address[] memory _rewardManagers,
uint256[] memory _rewardRates
)
CommunalFarm(_owner, _stakingToken, _rewardSymbols, _rewardTokens, _rewardManagers, _rewardRates)
{}
}
文件 4 的 13:Context.sol
pragma solidity >=0.6.11;
abstract contract Context {
function _msgSender() internal view virtual returns (address payable) {
return payable(msg.sender);
}
function _msgData() internal view virtual returns (bytes memory) {
this;
return msg.data;
}
}
文件 5 的 13:ERC20.sol
pragma solidity >=0.6.11;
import "./Context.sol";
import "./IERC20.sol";
import "./SafeMath.sol";
import "./Address.sol";
contract ERC20 is Context, IERC20 {
using SafeMath for uint256;
mapping (address => uint256) private _balances;
mapping (address => mapping (address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
uint8 private _decimals;
constructor (string memory __name, string memory __symbol) public {
_name = __name;
_symbol = __symbol;
_decimals = 18;
}
function name() public view returns (string memory) {
return _name;
}
function symbol() public view returns (string memory) {
return _symbol;
}
function decimals() public view returns (uint8) {
return _decimals;
}
function totalSupply() public view override returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) public view override returns (uint256) {
return _balances[account];
}
function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
_transfer(_msgSender(), recipient, amount);
return true;
}
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
function approve(address spender, uint256 amount) public virtual override returns (bool) {
_approve(_msgSender(), spender, amount);
return true;
}
function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
_transfer(sender, recipient, amount);
_approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
return true;
}
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
return true;
}
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
return true;
}
function _transfer(address sender, address recipient, uint256 amount) internal virtual {
require(sender != address(0), "ERC20: transfer from the zero address");
require(recipient != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(sender, recipient, amount);
_balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
_balances[recipient] = _balances[recipient].add(amount);
emit Transfer(sender, recipient, amount);
}
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply = _totalSupply.add(amount);
_balances[account] = _balances[account].add(amount);
emit Transfer(address(0), account, amount);
}
function burn(uint256 amount) public virtual {
_burn(_msgSender(), amount);
}
function burnFrom(address account, uint256 amount) public virtual {
uint256 decreasedAllowance = allowance(account, _msgSender()).sub(amount, "ERC20: burn amount exceeds allowance");
_approve(account, _msgSender(), decreasedAllowance);
_burn(account, amount);
}
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
_balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
_totalSupply = _totalSupply.sub(amount);
emit Transfer(account, address(0), amount);
}
function _approve(address owner, address spender, uint256 amount) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
function _burnFrom(address account, uint256 amount) internal virtual {
_burn(account, amount);
_approve(account, _msgSender(), _allowances[account][_msgSender()].sub(amount, "ERC20: burn amount exceeds allowance"));
}
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
}
文件 6 的 13:IERC20.sol
pragma solidity >=0.6.11;
import "./Context.sol";
import "./SafeMath.sol";
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);
}
文件 7 的 13:ISaddleD4_LP.sol
pragma solidity >=0.6.11;
interface ISaddleD4_LP {
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function balanceOf(address account) external view returns (uint256);
function burn(uint256 amount) external;
function burnFrom(address account, uint256 amount) external;
function decimals() external view returns (uint8);
function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool);
function increaseAllowance(address spender, uint256 addedValue) external returns (bool);
function initialize(string memory name, string memory symbol) external returns (bool);
function mint(address recipient, uint256 amount) external;
function name() external view returns (string memory);
function owner() external view returns (address);
function renounceOwnership() external;
function symbol() external view returns (string memory);
function totalSupply() external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
function transferOwnership(address newOwner) external;
}
文件 8 的 13:Math.sol
pragma solidity >=0.6.11;
library Math {
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a >= b ? a : b;
}
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
function average(uint256 a, uint256 b) internal pure returns (uint256) {
return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
}
function sqrt(uint y) internal pure returns (uint z) {
if (y > 3) {
z = y;
uint x = y / 2 + 1;
while (x < z) {
z = x;
x = (y / x + x) / 2;
}
} else if (y != 0) {
z = 1;
}
}
}
文件 9 的 13:Owned.sol
pragma solidity >=0.6.11;
contract Owned {
address public owner;
address public nominatedOwner;
constructor(address _owner) public {
require(_owner != address(0), "Owner address cannot be 0");
owner = _owner;
emit OwnerChanged(address(0), _owner);
}
function nominateNewOwner(address _owner) external onlyOwner {
nominatedOwner = _owner;
emit OwnerNominated(_owner);
}
function acceptOwnership() external {
require(msg.sender == nominatedOwner, "You must be nominated before you can accept ownership");
emit OwnerChanged(owner, nominatedOwner);
owner = nominatedOwner;
nominatedOwner = address(0);
}
modifier onlyOwner {
require(msg.sender == owner, "Only the contract owner may perform this action");
_;
}
event OwnerNominated(address newOwner);
event OwnerChanged(address oldOwner, address newOwner);
}
文件 10 的 13:ReentrancyGuard.sol
pragma solidity >=0.6.11;
abstract contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor () internal {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}
}
文件 11 的 13:SafeERC20.sol
pragma solidity >=0.6.11;
import "./IERC20.sol";
import "./SafeMath.sol";
import "./Address.sol";
library SafeERC20 {
using SafeMath for uint256;
using Address for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(IERC20 token, address spender, uint256 value) internal {
require((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));
}
function safeIncreaseAllowance(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));
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
文件 12 的 13:SafeMath.sol
pragma solidity >=0.6.11;
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;
}
}
文件 13 的 13:TransferHelper.sol
pragma solidity >=0.6.11;
library TransferHelper {
function safeApprove(address token, address to, uint value) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: APPROVE_FAILED');
}
function safeTransfer(address token, address to, uint value) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FAILED');
}
function safeTransferFrom(address token, address from, address to, uint value) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FROM_FAILED');
}
function safeTransferETH(address to, uint value) internal {
(bool success,) = to.call{value:value}(new bytes(0));
require(success, 'TransferHelper: ETH_TRANSFER_FAILED');
}
}
{
"compilationTarget": {
"CommunalFarm_SaddleD4.sol": "CommunalFarm_SaddleD4"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 100000
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_stakingToken","type":"address"},{"internalType":"string[]","name":"_rewardSymbols","type":"string[]"},{"internalType":"address[]","name":"_rewardTokens","type":"address[]"},{"internalType":"address[]","name":"_rewardManagers","type":"address[]"},{"internalType":"uint256[]","name":"_rewardRates","type":"uint256[]"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[],"name":"DefaultInitialization","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"multiplier","type":"uint256"}],"name":"LockedStakeMaxMultiplierUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"secs","type":"uint256"}],"name":"LockedStakeMinTime","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"secs","type":"uint256"}],"name":"LockedStakeTimeForMaxMultiplier","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerNominated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"destination_address","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Recovered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"},{"indexed":false,"internalType":"address","name":"token_address","type":"address"},{"indexed":false,"internalType":"address","name":"destination_address","type":"address"}],"name":"RewardPaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newDuration","type":"uint256"}],"name":"RewardsDurationUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"}],"name":"RewardsPeriodRenewed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"secs","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"kek_id","type":"bytes32"},{"indexed":false,"internalType":"address","name":"source_address","type":"address"}],"name":"StakeLocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"kek_id","type":"bytes32"},{"indexed":false,"internalType":"address","name":"destination_address","type":"address"}],"name":"WithdrawLocked","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"calcCurCombinedWeight","outputs":[{"internalType":"uint256","name":"old_combined_weight","type":"uint256"},{"internalType":"uint256","name":"new_combined_weight","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"reward_token_address","type":"address"},{"internalType":"address","name":"new_manager_address","type":"address"}],"name":"changeTokenManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"combinedWeightOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"earned","outputs":[{"internalType":"uint256[]","name":"new_earned","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllRewardTokens","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getReward","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getRewardForDuration","outputs":[{"internalType":"uint256[]","name":"rewards_per_duration_arr","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRewardSymbols","outputs":[{"internalType":"string[]","name":"","type":"string[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"greylist","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"greylistAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"initializeDefault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"caller_addr","type":"address"},{"internalType":"address","name":"reward_token_addr","type":"address"}],"name":"isTokenManagerFor","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastUpdateTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"secs","type":"uint256"}],"name":"lockMultiplier","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lock_max_multiplier","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lock_time_for_max_multiplier","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lock_time_min","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"lockedLiquidityOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"lockedStakesOf","outputs":[{"components":[{"internalType":"bytes32","name":"kek_id","type":"bytes32"},{"internalType":"uint256","name":"start_timestamp","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"ending_timestamp","type":"uint256"},{"internalType":"uint256","name":"lock_multiplier","type":"uint256"}],"internalType":"struct CommunalFarm.LockedStake[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"nominateNewOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nominatedOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"periodFinish","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"name":"recoverERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewardManagers","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rewardRates","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rewardSymbols","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewardTokenAddrToIdx","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rewardTokens","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsCollectionPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsPerToken","outputs":[{"internalType":"uint256[]","name":"newRewardsPerTokenStored","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lock_time_for_max_multiplier","type":"uint256"},{"internalType":"uint256","name":"_lock_time_min","type":"uint256"}],"name":"setLockedStakeTimeForMinAndMaxMultiplier","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lock_max_multiplier","type":"uint256"}],"name":"setMultipliers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"reward_token_address","type":"address"},{"internalType":"uint256","name":"new_rate","type":"uint256"},{"internalType":"bool","name":"sync_too","type":"bool"}],"name":"setRewardRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_rewardsDuration","type":"uint256"}],"name":"setRewardsDuration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"secs","type":"uint256"}],"name":"stakeLocked","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stakesUnlocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stakingPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sync","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"toggleRewardsCollection","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"toggleStaking","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"toggleWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalCombinedWeight","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalLiquidityLocked","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unlockStakes","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"kek_id","type":"bytes32"}],"name":"withdrawLocked","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawalsPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]