Source Code
Overview
S Balance
0 S
More Info
ContractCreator
Loading...
Loading
Contract Name:
MultiFeeDistribution
Compiler Version
v0.7.6+commit.7338295f
Optimization Enabled:
Yes with 2000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
pragma solidity 0.7.6; pragma abicoder v2; import "../interfaces/IChefIncentivesController.sol"; import "../interfaces/IMultiFeeDistribution.sol"; import "../dependencies/openzeppelin/contracts/IERC20.sol"; import "../dependencies/openzeppelin/contracts/SafeERC20.sol"; import "../dependencies/openzeppelin/contracts/SafeMath.sol"; import "../dependencies/openzeppelin/contracts/Ownable.sol"; interface IMintableToken is IERC20 { function mint(address _receiver, uint256 _amount) external returns (bool); function setMinter(address _minter) external returns (bool); } // Based on Ellipsis EPS Staker // https://github.com/ellipsis-finance/ellipsis/blob/master/contracts/EpsStaker.sol contract MultiFeeDistribution is IMultiFeeDistribution, Ownable { using SafeMath for uint256; using SafeERC20 for IERC20; using SafeERC20 for IMintableToken; /* ========== STATE VARIABLES ========== */ struct Reward { uint256 periodFinish; uint256 rewardRate; uint256 lastUpdateTime; uint256 rewardPerTokenStored; // tracks already-added balances to handle accrued interest in aToken rewards // for the stakingToken this value is unused and will always be 0 uint256 balance; } struct Balances { uint256 total; uint256 unlocked; uint256 locked; uint256 earned; } struct LockedBalance { uint256 amount; uint256 unlockTime; } struct RewardData { address token; uint256 amount; } IChefIncentivesController public incentivesController; IMintableToken public immutable stakingToken; address[] public rewardTokens; mapping(address => Reward) public rewardData; // Duration that rewards are streamed over uint256 public constant rewardsDuration = 86400 * 7; // Duration of lock/earned penalty period uint256 public constant lockDuration = rewardsDuration * 13; // Addresses approved to call mint mapping(address => bool) public minters; bool public mintersAreSet; // user -> reward token -> amount mapping(address => mapping(address => uint256)) public userRewardPerTokenPaid; mapping(address => mapping(address => uint256)) public rewards; uint256 public totalSupply; uint256 public lockedSupply; // Private mappings for balance data mapping(address => Balances) private balances; mapping(address => LockedBalance[]) private userLocks; mapping(address => LockedBalance[]) private userEarnings; /* ========== CONSTRUCTOR ========== */ constructor(address _stakingToken) Ownable() { stakingToken = IMintableToken(_stakingToken); IMintableToken(_stakingToken).setMinter(address(this)); // First reward MUST be the staking token or things will break // related to the 50% penalty and distribution to locked balances rewardTokens.push(_stakingToken); rewardData[_stakingToken].lastUpdateTime = block.timestamp; } /* ========== ADMIN CONFIGURATION ========== */ function setMinters(address[] memory _minters) external onlyOwner { require(!mintersAreSet); for (uint i; i < _minters.length; i++) { minters[_minters[i]] = true; } mintersAreSet = true; } function setIncentivesController(IChefIncentivesController _controller) external onlyOwner { incentivesController = _controller; } // Add a new reward token to be distributed to stakers function addReward(address _rewardsToken) external override onlyOwner { require(rewardData[_rewardsToken].lastUpdateTime == 0); rewardTokens.push(_rewardsToken); rewardData[_rewardsToken].lastUpdateTime = block.timestamp; rewardData[_rewardsToken].periodFinish = block.timestamp; } /* ========== VIEWS ========== */ function _rewardPerToken(address _rewardsToken, uint256 _supply) internal view returns (uint256) { if (_supply == 0) { return rewardData[_rewardsToken].rewardPerTokenStored; } return rewardData[_rewardsToken].rewardPerTokenStored.add( lastTimeRewardApplicable(_rewardsToken).sub( rewardData[_rewardsToken].lastUpdateTime).mul( rewardData[_rewardsToken].rewardRate).mul(1e18).div(_supply) ); } function _earned( address _user, address _rewardsToken, uint256 _balance, uint256 _currentRewardPerToken ) internal view returns (uint256) { return _balance.mul( _currentRewardPerToken.sub(userRewardPerTokenPaid[_user][_rewardsToken]) ).div(1e18).add(rewards[_user][_rewardsToken]); } function lastTimeRewardApplicable(address _rewardsToken) public view returns (uint256) { uint periodFinish = rewardData[_rewardsToken].periodFinish; return block.timestamp < periodFinish ? block.timestamp : periodFinish; } function rewardPerToken(address _rewardsToken) external view returns (uint256) { uint256 supply = _rewardsToken == address(stakingToken) ? lockedSupply : totalSupply; return _rewardPerToken(_rewardsToken, supply); } function getRewardForDuration(address _rewardsToken) external view returns (uint256) { return rewardData[_rewardsToken].rewardRate.mul(rewardsDuration).div(1e12); } // Address and claimable amount of all reward tokens for the given account function claimableRewards(address account) external view returns (RewardData[] memory rewards) { rewards = new RewardData[](rewardTokens.length); for (uint256 i = 0; i < rewards.length; i++) { // If i == 0 this is the stakingReward, distribution is based on locked balances uint256 balance = i == 0 ? balances[account].locked : balances[account].total; uint256 supply = i == 0 ? lockedSupply : totalSupply; rewards[i].token = rewardTokens[i]; rewards[i].amount = _earned(account, rewards[i].token, balance, _rewardPerToken(rewardTokens[i], supply)).div(1e12); } return rewards; } // Total balance of an account, including unlocked, locked and earned tokens function totalBalance(address user) view external returns (uint256 amount) { return balances[user].total; } // Total withdrawable balance for an account to which no penalty is applied function unlockedBalance(address user) view external returns (uint256 amount) { amount = balances[user].unlocked; LockedBalance[] storage earnings = userEarnings[msg.sender]; for (uint i = 0; i < earnings.length; i++) { if (earnings[i].unlockTime > block.timestamp) { break; } amount = amount.add(earnings[i].amount); } return amount; } // Information on the "earned" balances of a user // Earned balances may be withdrawn immediately for a 50% penalty function earnedBalances( address user ) view external returns ( uint256 total, LockedBalance[] memory earningsData ) { LockedBalance[] storage earnings = userEarnings[user]; uint256 idx; for (uint i = 0; i < earnings.length; i++) { if (earnings[i].unlockTime > block.timestamp) { if (idx == 0) { earningsData = new LockedBalance[](earnings.length - i); } earningsData[idx] = earnings[i]; idx++; total = total.add(earnings[i].amount); } } return (total, earningsData); } // Information on a user's locked balances function lockedBalances( address user ) view external returns ( uint256 total, uint256 unlockable, uint256 locked, LockedBalance[] memory lockData ) { LockedBalance[] storage locks = userLocks[user]; uint256 idx; for (uint i = 0; i < locks.length; i++) { if (locks[i].unlockTime > block.timestamp) { if (idx == 0) { lockData = new LockedBalance[](locks.length - i); } lockData[idx] = locks[i]; idx++; locked = locked.add(locks[i].amount); } else { unlockable = unlockable.add(locks[i].amount); } } return (balances[user].locked, unlockable, locked, lockData); } // Final balance received and penalty balance paid by user upon calling exit function withdrawableBalance( address user ) view public returns ( uint256 amount, uint256 penaltyAmount ) { Balances storage bal = balances[user]; uint256 earned = bal.earned; if (earned > 0) { uint256 amountWithoutPenalty; uint256 length = userEarnings[user].length; for (uint i = 0; i < length; i++) { uint256 earnedAmount = userEarnings[user][i].amount; if (earnedAmount == 0) continue; if (userEarnings[user][i].unlockTime > block.timestamp) { break; } amountWithoutPenalty = amountWithoutPenalty.add(earnedAmount); } penaltyAmount = earned.sub(amountWithoutPenalty).div(2); } amount = bal.unlocked.add(earned).sub(penaltyAmount); return (amount, penaltyAmount); } /* ========== MUTATIVE FUNCTIONS ========== */ // Stake tokens to receive rewards // Locked tokens cannot be withdrawn for lockDuration and are eligible to receive stakingReward rewards function stake(uint256 amount, bool lock) external { require(amount > 0, "Cannot stake 0"); _updateReward(msg.sender); totalSupply = totalSupply.add(amount); Balances storage bal = balances[msg.sender]; bal.total = bal.total.add(amount); if (lock) { lockedSupply = lockedSupply.add(amount); bal.locked = bal.locked.add(amount); uint256 unlockTime = block.timestamp.div(rewardsDuration).mul(rewardsDuration).add(lockDuration); uint256 idx = userLocks[msg.sender].length; if (idx == 0 || userLocks[msg.sender][idx-1].unlockTime < unlockTime) { userLocks[msg.sender].push(LockedBalance({amount: amount, unlockTime: unlockTime})); } else { userLocks[msg.sender][idx-1].amount = userLocks[msg.sender][idx-1].amount.add(amount); } } else { bal.unlocked = bal.unlocked.add(amount); } stakingToken.safeTransferFrom(msg.sender, address(this), amount); emit Staked(msg.sender, amount, lock); } // Mint new tokens // Minted tokens receive rewards normally but incur a 50% penalty when // withdrawn before lockDuration has passed. function mint(address user, uint256 amount, bool withPenalty) external override { require(minters[msg.sender]); if (amount == 0) return; _updateReward(user); stakingToken.mint(address(this), amount); if (user == address(this)) { // minting to this contract adds the new tokens as incentives for lockers _notifyReward(address(stakingToken), amount); return; } totalSupply = totalSupply.add(amount); Balances storage bal = balances[user]; bal.total = bal.total.add(amount); if (withPenalty) { bal.earned = bal.earned.add(amount); uint256 unlockTime = block.timestamp.div(rewardsDuration).mul(rewardsDuration).add(lockDuration); LockedBalance[] storage earnings = userEarnings[user]; uint256 idx = earnings.length; if (idx == 0 || earnings[idx-1].unlockTime < unlockTime) { earnings.push(LockedBalance({amount: amount, unlockTime: unlockTime})); } else { earnings[idx-1].amount = earnings[idx-1].amount.add(amount); } } else { bal.unlocked = bal.unlocked.add(amount); } emit Staked(user, amount, false); } // Withdraw staked tokens // First withdraws unlocked tokens, then earned tokens. Withdrawing earned tokens // incurs a 50% penalty which is distributed based on locked balances. function withdraw(uint256 amount) public { require(amount > 0, "Cannot withdraw 0"); _updateReward(msg.sender); Balances storage bal = balances[msg.sender]; uint256 penaltyAmount; if (amount <= bal.unlocked) { bal.unlocked = bal.unlocked.sub(amount); } else { uint256 remaining = amount.sub(bal.unlocked); require(bal.earned >= remaining, "Insufficient unlocked balance"); bal.unlocked = 0; bal.earned = bal.earned.sub(remaining); for (uint i = 0; ; i++) { uint256 earnedAmount = userEarnings[msg.sender][i].amount; if (earnedAmount == 0) continue; if (penaltyAmount == 0 && userEarnings[msg.sender][i].unlockTime > block.timestamp) { penaltyAmount = remaining; require(bal.earned >= remaining, "Insufficient balance after penalty"); bal.earned = bal.earned.sub(remaining); if (bal.earned == 0) { delete userEarnings[msg.sender]; break; } remaining = remaining.mul(2); } if (remaining <= earnedAmount) { userEarnings[msg.sender][i].amount = earnedAmount.sub(remaining); break; } else { delete userEarnings[msg.sender][i]; remaining = remaining.sub(earnedAmount); } } } uint256 adjustedAmount = amount.add(penaltyAmount); bal.total = bal.total.sub(adjustedAmount); totalSupply = totalSupply.sub(adjustedAmount); stakingToken.safeTransfer(msg.sender, amount); if (penaltyAmount > 0) { incentivesController.claim(address(this), new address[](0)); _notifyReward(address(stakingToken), penaltyAmount); } emit Withdrawn(msg.sender, amount, penaltyAmount); } function _getReward(address[] memory _rewardTokens) internal { uint256 length = _rewardTokens.length; for (uint i; i < length; i++) { address token = _rewardTokens[i]; uint256 reward = rewards[msg.sender][token].div(1e12); if (token != address(stakingToken)) { // for rewards other than stakingToken, every 24 hours we check if new // rewards were sent to the contract or accrued via aToken interest Reward storage r = rewardData[token]; uint256 periodFinish = r.periodFinish; require(periodFinish > 0, "Unknown reward token"); uint256 balance = r.balance; if (periodFinish < block.timestamp.add(rewardsDuration - 86400)) { uint256 unseen = IERC20(token).balanceOf(address(this)).sub(balance); if (unseen > 0) { _notifyReward(token, unseen); balance = balance.add(unseen); } } r.balance = balance.sub(reward); } if (reward == 0) continue; rewards[msg.sender][token] = 0; IERC20(token).safeTransfer(msg.sender, reward); emit RewardPaid(msg.sender, token, reward); } } // Claim all pending staking rewards function getReward(address[] memory _rewardTokens) public { _updateReward(msg.sender); _getReward(_rewardTokens); } // Withdraw full unlocked balance and optionally claim pending rewards function exit(bool claimRewards) external { _updateReward(msg.sender); (uint256 amount, uint256 penaltyAmount) = withdrawableBalance(msg.sender); delete userEarnings[msg.sender]; Balances storage bal = balances[msg.sender]; bal.total = bal.total.sub(bal.unlocked).sub(bal.earned); bal.unlocked = 0; bal.earned = 0; totalSupply = totalSupply.sub(amount.add(penaltyAmount)); stakingToken.safeTransfer(msg.sender, amount); if (penaltyAmount > 0) { incentivesController.claim(address(this), new address[](0)); _notifyReward(address(stakingToken), penaltyAmount); } if (claimRewards) { _getReward(rewardTokens); } emit Withdrawn(msg.sender, amount, penaltyAmount); } // Withdraw all currently locked tokens where the unlock time has passed function withdrawExpiredLocks() external { _updateReward(msg.sender); LockedBalance[] storage locks = userLocks[msg.sender]; Balances storage bal = balances[msg.sender]; uint256 amount; uint256 length = locks.length; if (locks[length-1].unlockTime <= block.timestamp) { amount = bal.locked; delete userLocks[msg.sender]; } else { for (uint i = 0; i < length; i++) { if (locks[i].unlockTime > block.timestamp) break; amount = amount.add(locks[i].amount); delete locks[i]; } } bal.locked = bal.locked.sub(amount); bal.total = bal.total.sub(amount); totalSupply = totalSupply.sub(amount); lockedSupply = lockedSupply.sub(amount); stakingToken.safeTransfer(msg.sender, amount); emit Withdrawn(msg.sender, amount, 0); } /* ========== RESTRICTED FUNCTIONS ========== */ function _notifyReward(address _rewardsToken, uint256 reward) internal { Reward storage r = rewardData[_rewardsToken]; if (block.timestamp >= r.periodFinish) { r.rewardRate = reward.mul(1e12).div(rewardsDuration); } else { uint256 remaining = r.periodFinish.sub(block.timestamp); uint256 leftover = remaining.mul(r.rewardRate).div(1e12); r.rewardRate = reward.add(leftover).mul(1e12).div(rewardsDuration); } r.lastUpdateTime = block.timestamp; r.periodFinish = block.timestamp.add(rewardsDuration); } // Added to support recovering LP Rewards from other systems such as BAL to be distributed to holders function recoverERC20(address tokenAddress, uint256 tokenAmount) external onlyOwner { require(tokenAddress != address(stakingToken), "Cannot withdraw staking token"); require(rewardData[tokenAddress].lastUpdateTime == 0, "Cannot withdraw reward token"); IERC20(tokenAddress).safeTransfer(owner(), tokenAmount); emit Recovered(tokenAddress, tokenAmount); } function _updateReward(address account) internal { address token = address(stakingToken); uint256 balance; Reward storage r = rewardData[token]; uint256 rpt = _rewardPerToken(token, lockedSupply); r.rewardPerTokenStored = rpt; r.lastUpdateTime = lastTimeRewardApplicable(token); if (account != address(this)) { // Special case, use the locked balances and supply for stakingReward rewards rewards[account][token] = _earned(account, token, balances[account].locked, rpt); userRewardPerTokenPaid[account][token] = rpt; balance = balances[account].total; } uint256 supply = totalSupply; uint256 length = rewardTokens.length; for (uint i = 1; i < length; i++) { token = rewardTokens[i]; r = rewardData[token]; rpt = _rewardPerToken(token, supply); r.rewardPerTokenStored = rpt; r.lastUpdateTime = lastTimeRewardApplicable(token); if (account != address(this)) { rewards[account][token] = _earned(account, token, balance, rpt); userRewardPerTokenPaid[account][token] = rpt; } } } /* ========== EVENTS ========== */ event RewardAdded(uint256 reward); event Staked(address indexed user, uint256 amount, bool locked); event Withdrawn(address indexed user, uint256 receivedAmount, uint256 penaltyPaid); event RewardPaid(address indexed user, address indexed rewardsToken, uint256 reward); event RewardsDurationUpdated(address token, uint256 newDuration); event Recovered(address token, uint256 amount); }
// SPDX-License-Identifier: agpl-3.0 pragma solidity 0.7.6; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // According to EIP-1052, 0x0 is the value returned for not-yet created accounts // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned // for accounts without code, i.e. `keccak256('')` bytes32 codehash; bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; // solhint-disable-next-line no-inline-assembly assembly { codehash := extcodehash(account) } return (codehash != accountHash && codehash != 0x0); } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, 'Address: insufficient balance'); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{value: amount}(''); require(success, 'Address: unable to send value, recipient may have reverted'); } }
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with GSN meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address payable) { return msg.sender; } function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } }
// SPDX-License-Identifier: agpl-3.0 pragma solidity 0.7.6; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (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. */ function transfer(address recipient, uint256 amount) external returns (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. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: 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. */ function approve(address spender, uint256 amount) external returns (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. */ function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed 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. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import './Context.sol'; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { address msgSender = _msgSender(); _owner = msgSender; emit OwnershipTransferred(address(0), msgSender); } /** * @dev Returns the address of the current owner. */ function owner() public view returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(_owner == _msgSender(), 'Ownable: caller is not the owner'); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), 'Ownable: new owner is the zero address'); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } }
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; import {IERC20} from './IERC20.sol'; import {SafeMath} from './SafeMath.sol'; import {Address} from './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 IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ 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 callOptionalReturn(IERC20 token, bytes memory data) private { require(address(token).isContract(), 'SafeERC20: call to non-contract'); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory 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-length require(abi.decode(returndata, (bool)), 'SafeERC20: ERC20 operation did not succeed'); } } }
// SPDX-License-Identifier: agpl-3.0 pragma solidity 0.7.6; /** * @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. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (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. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, 'SafeMath: subtraction overflow'); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. */ function sub( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { require(b <= a, errorMessage); 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. */ function mul(uint256 a, uint256 b) internal pure returns (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-contracts/pull/522 if (a == 0) { return 0; } 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. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, 'SafeMath: division by zero'); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message 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. */ function div( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return 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. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, 'SafeMath: modulo by zero'); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message 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. */ function mod( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } }
// SPDX-License-Identifier: agpl-3.0 pragma solidity 0.7.6; pragma experimental ABIEncoderV2; interface IChefIncentivesController { /** * @dev Called by the corresponding asset on any update that affects the rewards distribution * @param user The address of the user * @param userBalance The balance of the user of the asset in the lending pool * @param totalSupply The total supply of the asset in the lending pool **/ function handleAction( address user, uint256 userBalance, uint256 totalSupply ) external; function addPool(address _token, uint256 _allocPoint) external; function claim(address _user, address[] calldata _tokens) external; function setClaimReceiver(address _user, address _receiver) external; }
pragma solidity 0.7.6; interface IMultiFeeDistribution { function addReward(address rewardsToken) external; function mint(address user, uint256 amount, bool withPenalty) external; }
{ "optimizer": { "enabled": true, "runs": 2000 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": {} }
[{"inputs":[{"internalType":"address","name":"_stakingToken","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Recovered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"}],"name":"RewardAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"rewardsToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"}],"name":"RewardPaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"newDuration","type":"uint256"}],"name":"RewardsDurationUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"locked","type":"bool"}],"name":"Staked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"receivedAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"penaltyPaid","type":"uint256"}],"name":"Withdrawn","type":"event"},{"inputs":[{"internalType":"address","name":"_rewardsToken","type":"address"}],"name":"addReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"claimableRewards","outputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct MultiFeeDistribution.RewardData[]","name":"rewards","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"earnedBalances","outputs":[{"internalType":"uint256","name":"total","type":"uint256"},{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"unlockTime","type":"uint256"}],"internalType":"struct MultiFeeDistribution.LockedBalance[]","name":"earningsData","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"claimRewards","type":"bool"}],"name":"exit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_rewardTokens","type":"address[]"}],"name":"getReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_rewardsToken","type":"address"}],"name":"getRewardForDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"incentivesController","outputs":[{"internalType":"contract IChefIncentivesController","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_rewardsToken","type":"address"}],"name":"lastTimeRewardApplicable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lockDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"lockedBalances","outputs":[{"internalType":"uint256","name":"total","type":"uint256"},{"internalType":"uint256","name":"unlockable","type":"uint256"},{"internalType":"uint256","name":"locked","type":"uint256"},{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"unlockTime","type":"uint256"}],"internalType":"struct MultiFeeDistribution.LockedBalance[]","name":"lockData","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lockedSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"withPenalty","type":"bool"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"minters","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mintersAreSet","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"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":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewardData","outputs":[{"internalType":"uint256","name":"periodFinish","type":"uint256"},{"internalType":"uint256","name":"rewardRate","type":"uint256"},{"internalType":"uint256","name":"lastUpdateTime","type":"uint256"},{"internalType":"uint256","name":"rewardPerTokenStored","type":"uint256"},{"internalType":"uint256","name":"balance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_rewardsToken","type":"address"}],"name":"rewardPerToken","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":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"rewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IChefIncentivesController","name":"_controller","type":"address"}],"name":"setIncentivesController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_minters","type":"address[]"}],"name":"setMinters","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"lock","type":"bool"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stakingToken","outputs":[{"internalType":"contract IMintableToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"totalBalance","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"unlockedBalance","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"userRewardPerTokenPaid","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawExpiredLocks","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"withdrawableBalance","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"penaltyAmount","type":"uint256"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60a06040523480156200001157600080fd5b50604051620032bf380380620032bf833981016040819052620000349162000187565b60006200004062000183565b600080546001600160a01b0319166001600160a01b0383169081178255604051929350917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3506001600160601b0319606082901b16608052604051637e51dad560e11b81526001600160a01b0382169063fca3b5aa90620000ca903090600401620001d9565b602060405180830381600087803b158015620000e557600080fd5b505af1158015620000fa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001209190620001b7565b50600280546001810182557f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace0180546001600160a01b039093166001600160a01b03199093168317905560009182526003602052604090912042910155620001ed565b3390565b60006020828403121562000199578081fd5b81516001600160a01b0381168114620001b0578182fd5b9392505050565b600060208284031215620001c9578081fd5b81518015158114620001b0578182fd5b6001600160a01b0391909116815260200190565b60805160601c6130786200024760003980610a015280610ac05280610e0a5280610ed752806112095280611448528061156652806116065280611ba45280611c635280611d4e5280611fa9528061235552506130786000f3fe608060405234801561001057600080fd5b50600436106102265760003560e01c80638da5cb5b1161012a578063d1a1beb4116100bd578063e6c91a151161008c578063f122977711610071578063f122977714610486578063f2fde38b14610499578063f46eccc4146104ac57610226565b8063e6c91a1514610460578063e70b9e271461047357610226565b8063d1a1beb4146103f9578063dc01f60d1461040c578063df3798761461042c578063e655dbd81461044d57610226565b8063abe50f19116100f9578063abe50f19146103c3578063af1df255146103d6578063bcd11014146103de578063ca5c7b91146103f157610226565b80638da5cb5b1461038b5780638fd9f2ca146103935780639c9b2e21146103a8578063a01c77bc146103bb57610226565b80635e0fac2e116101bd578063715018a61161018c5780637bb7bed1116101715780637bb7bed1146103525780637fd7d062146103655780638980f11f1461037857610226565b8063715018a61461033557806372f702f31461033d57610226565b80635e0fac2e146102e9578063638634ee146102fc5780636eacd3981461030f5780637035ab981461032257610226565b80632e1a7d4d116101f95780632e1a7d4d14610295578063386a9525146102aa57806348e5d9f8146102b2578063547d0096146102d657610226565b806302b629381461022b57806304554443146102555780630483a7f61461026a57806318160ddd1461028d575b600080fd5b61023e610239366004612a45565b6104bf565b60405161024c929190612f4e565b60405180910390f35b61025d6105ef565b60405161024c9190612f1c565b61027d610278366004612a45565b6105f6565b60405161024c9493929190612f5c565b61025d610784565b6102a86102a3366004612bf2565b61078a565b005b61025d610b2e565b6102c56102c0366004612a45565b610b35565b60405161024c959493929190612f8b565b6102a86102e4366004612b05565b610b65565b61025d6102f7366004612a45565b610c48565b61025d61030a366004612a45565b610ce0565b61025d61031d366004612a45565b610d0f565b61025d610330366004612a61565b610d2a565b6102a8610d47565b610345610e08565b60405161024c9190612c8b565b610345610360366004612bf2565b610e2c565b6102a8610373366004612b05565b610e56565b6102a8610386366004612a99565b610e6b565b610345610fb9565b61039b610fc8565b60405161024c9190612d6a565b6102a86103b6366004612a45565b610fd1565b6102a86110d0565b6102a86103d1366004612c22565b61126c565b6103456114b8565b61025d6103ec366004612a45565b6114c7565b61025d611501565b6102a8610407366004612ac4565b611507565b61041f61041a366004612a45565b6117b8565b60405161024c9190612d12565b61043f61043a366004612a45565b611953565b60405161024c929190612f25565b6102a861045b366004612a45565b611a77565b6102a861046e366004612bba565b611b10565b61025d610481366004612a61565b611d2c565b61025d610494366004612a45565b611d49565b6102a86104a7366004612a45565b611d9d565b61039b6104ba366004612a45565b611eb4565b6001600160a01b0381166000908152600a60205260408120600381015482919080156105c5576001600160a01b0385166000908152600c6020526040812054815b818110156105aa576001600160a01b0388166000908152600c6020526040812080548390811061052c57fe5b9060005260206000209060020201600001549050806000141561054f57506105a2565b6001600160a01b0389166000908152600c6020526040902080544291908490811061057657fe5b906000526020600020906002020160010154111561059457506105aa565b61059e8482611ec9565b9350505b600101610500565b506105c060026105ba8585611f23565b90611f65565b945050505b6105e6836105e0838560010154611ec990919063ffffffff16565b90611f23565b93505050915091565b6277f88081565b6001600160a01b0381166000908152600b602052604081208190819060609082805b825481101561075c574283828154811061062e57fe5b906000526020600020906002020160010154111561072a57816106a457825481900367ffffffffffffffff8111801561066657600080fd5b506040519080825280602002602001820160405280156106a057816020015b61068d6129c9565b8152602001906001900390816106855790505b5093505b8281815481106106b057fe5b9060005260206000209060020201604051806040016040529081600082015481526020016001820154815250508483815181106106e957fe5b6020026020010181905250818060010192505061072383828154811061070b57fe5b60009182526020909120600290910201548690611ec9565b9450610754565b61075183828154811061073957fe5b60009182526020909120600290910201548790611ec9565b95505b600101610618565b5050506001600160a01b0385166000908152600a602052604090206002015493509193509193565b60085481565b600081116107b35760405162461bcd60e51b81526004016107aa90612e09565b60405180910390fd5b6107bc33611fa7565b336000908152600a60205260408120600181015490919083116107f25760018201546107e89084611f23565b60018301556109c7565b600061080b836001015485611f2390919063ffffffff16565b905080836003015410156108315760405162461bcd60e51b81526004016107aa90612e77565b6000600184015560038301546108479082611f23565b600384015560005b336000908152600c6020526040812080548390811061086a57fe5b9060005260206000209060020201600001549050806000141561088d57506109bc565b831580156108c85750336000908152600c602052604090208054429190849081106108b457fe5b906000526020600020906002020160010154115b1561093a5782935082856003015410156108f45760405162461bcd60e51b81526004016107aa90612dac565b60038501546109039084611f23565b6003860181905561092c57336000908152600c60205260408120610926916129e3565b506109c4565b610937836002612167565b92505b80831161097d5761094b8184611f23565b336000908152600c6020526040902080548490811061096657fe5b6000918252602090912060029091020155506109c4565b336000908152600c6020526040902080548390811061099857fe5b600091825260208220600290910201818155600101556109b88382611f23565b9250505b60010161084f565b50505b60006109d38483611ec9565b83549091506109e29082611f23565b83556008546109f19082611f23565b600855610a286001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633866121c0565b8115610ae5576001546001600160a01b0316638e2eba09306000604051908082528060200260200182016040528015610a6b578160200160208202803683370190505b506040518363ffffffff1660e01b8152600401610a89929190612c9f565b600060405180830381600087803b158015610aa357600080fd5b505af1158015610ab7573d6000803e3d6000fd5b50505050610ae57f000000000000000000000000000000000000000000000000000000000000000083612240565b336001600160a01b03167f92ccf450a286a957af52509bc1c9939d1a6a481783e142e41e2499f0bb66ebc68584604051610b20929190612f4e565b60405180910390a250505050565b62093a8081565b60036020819052600091825260409091208054600182015460028301549383015460049093015491939092909185565b610b6d6122f2565b6000546001600160a01b03908116911614610bcf576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b60055460ff1615610bdf57600080fd5b60005b8151811015610c3757600160046000848481518110610bfd57fe5b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff1916911515919091179055600101610be2565b50506005805460ff19166001179055565b6001600160a01b0381166000908152600a6020908152604080832060010154338452600c909252822090915b8154811015610cd85742828281548110610c8a57fe5b9060005260206000209060020201600101541115610ca757610cd8565b610cce828281548110610cb657fe5b60009182526020909120600290910201548490611ec9565b9250600101610c74565b50505b919050565b6001600160a01b038116600090815260036020526040812054428111610d065780610d08565b425b9392505050565b6001600160a01b03166000908152600a602052604090205490565b600660209081526000928352604080842090915290825290205481565b610d4f6122f2565b6000546001600160a01b03908116911614610db1576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a36000805473ffffffffffffffffffffffffffffffffffffffff19169055565b7f000000000000000000000000000000000000000000000000000000000000000081565b60028181548110610e3c57600080fd5b6000918252602090912001546001600160a01b0316905081565b610e5f33611fa7565b610e68816122f6565b50565b610e736122f2565b6000546001600160a01b03908116911614610ed5576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161415610f275760405162461bcd60e51b81526004016107aa90612e40565b6001600160a01b03821660009081526003602052604090206002015415610f605760405162461bcd60e51b81526004016107aa90612eae565b610f7c610f6b610fb9565b6001600160a01b03841690836121c0565b7f8c1256b8896378cd5044f80c202f9772b9d77dc85c8a6eb51967210b09bfaa288282604051610fad929190612cf9565b60405180910390a15050565b6000546001600160a01b031690565b60055460ff1681565b610fd96122f2565b6000546001600160a01b0390811691161461103b576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6001600160a01b0381166000908152600360205260409020600201541561106157600080fd5b600280546001810182557f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace0180546001600160a01b0390931673ffffffffffffffffffffffffffffffffffffffff19909316831790556000918252600360205260409091204291810182905555565b6110d933611fa7565b336000908152600b60209081526040808320600a90925282208154919290914284600019830183811061110857fe5b90600052602060002090600202016001015411611145576002830154336000908152600b6020526040812091935061114091906129e3565b6111ba565b60005b818110156111b8574285828154811061115d57fe5b906000526020600020906002020160010154111561117a576111b8565b611189858281548110610cb657fe5b925084818154811061119757fe5b60009182526020822060029091020181815560019081019190915501611148565b505b60028301546111c99083611f23565b600284015582546111da9083611f23565b83556008546111e99083611f23565b6008556009546111f99083611f23565b6009556112306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633846121c0565b336001600160a01b03167f92ccf450a286a957af52509bc1c9939d1a6a481783e142e41e2499f0bb66ebc6836000604051610b20929190612f4e565b6000821161128c5760405162461bcd60e51b81526004016107aa90612d75565b61129533611fa7565b6008546112a29083611ec9565b600855336000908152600a6020526040902080546112c09084611ec9565b81558115611426576009546112d59084611ec9565b60095560028101546112e79084611ec9565b600282015560006113126277f88061130c62093a806113064282611f65565b90612167565b90611ec9565b336000908152600b60205260409020549091508015806113635750336000908152600b602052604090208054839190600019840190811061134f57fe5b906000526020600020906002020160010154105b156113b257336000908152600b6020908152604080832081518083019092528882528183018681528154600181810184559286529390942091516002909302909101918255915191015561141f565b336000908152600b6020526040902080546113ee91879160001985019081106113d757fe5b600091825260209091206002909102015490611ec9565b336000908152600b602052604090208054600019840190811061140d57fe5b60009182526020909120600290910201555b505061143b565b60018101546114359084611ec9565b60018201555b6114706001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016333086612528565b336001600160a01b03167f37d4053e34fde482e96f6bcd424dfa31342cbd5fe184d497fb3c8bb4b4b9758084846040516114ab929190612f3e565b60405180910390a2505050565b6001546001600160a01b031681565b6001600160a01b0381166000908152600360205260408120600101546114fb9064e8d4a51000906105ba9062093a80612167565b92915050565b60095481565b3360009081526004602052604090205460ff1661152357600080fd5b8161152d576117b3565b61153683611fa7565b6040517f40c10f190000000000000000000000000000000000000000000000000000000081526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906340c10f199061159d9030908690600401612cf9565b602060405180830381600087803b1580156115b757600080fd5b505af11580156115cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115ef9190612bd6565b506001600160a01b0383163014156116305761162b7f000000000000000000000000000000000000000000000000000000000000000083612240565b6117b3565b60085461163d9083611ec9565b6008556001600160a01b0383166000908152600a6020526040902080546116649084611ec9565b8155811561176257600381015461167b9084611ec9565b6003820155600061169a6277f88061130c62093a806113064282611f65565b6001600160a01b0386166000908152600c602052604090208054919250908015806116e45750828260018303815481106116d057fe5b906000526020600020906002020160010154105b1561172657604080518082019091528681526020808201858152845460018181018755600087815293909320935160029091029093019283555191015561175a565b611739868360018403815481106113d757fe5b82600183038154811061174857fe5b60009182526020909120600290910201555b505050611777565b60018101546117719084611ec9565b60018201555b836001600160a01b03167f37d4053e34fde482e96f6bcd424dfa31342cbd5fe184d497fb3c8bb4b4b97580846000604051610b20929190612f3e565b505050565b60025460609067ffffffffffffffff811180156117d457600080fd5b5060405190808252806020026020018201604052801561180e57816020015b6117fb612a04565b8152602001906001900390816117f35790505b50905060005b815181101561194d5760008115611843576001600160a01b0384166000908152600a6020526040902054611860565b6001600160a01b0384166000908152600a60205260409020600201545b90506000821561187257600854611876565b6009545b90506002838154811061188557fe5b9060005260206000200160009054906101000a90046001600160a01b03168484815181106118af57fe5b6020026020010151600001906001600160a01b031690816001600160a01b03168152505061192964e8d4a510006105ba878787815181106118ec57fe5b6020026020010151600001518661192460028a8154811061190957fe5b6000918252602090912001546001600160a01b0316886125b6565b61264d565b84848151811061193557fe5b60209081029190910181015101525050600101611814565b50919050565b6001600160a01b0381166000908152600c6020526040812060609082805b8254811015611a6f574283828154811061198757fe5b9060005260206000209060020201600101541115611a6757816119fd57825481900367ffffffffffffffff811180156119bf57600080fd5b506040519080825280602002602001820160405280156119f957816020015b6119e66129c9565b8152602001906001900390816119de5790505b5093505b828181548110611a0957fe5b906000526020600020906002020160405180604001604052908160008201548152602001600182015481525050848381518110611a4257fe5b60200260200101819052508180600101925050611a6483828154811061070b57fe5b94505b600101611971565b505050915091565b611a7f6122f2565b6000546001600160a01b03908116911614611ae1576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6001805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b611b1933611fa7565b600080611b25336104bf565b336000908152600c60205260408120929450909250611b4491906129e3565b336000908152600a60205260409020600381015460018201548254611b6e92916105e09190611f23565b81556000600182018190556003820155611b94611b8b8484611ec9565b60085490611f23565b600855611bcb6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633856121c0565b8115611c88576001546001600160a01b0316638e2eba09306000604051908082528060200260200182016040528015611c0e578160200160208202803683370190505b506040518363ffffffff1660e01b8152600401611c2c929190612c9f565b600060405180830381600087803b158015611c4657600080fd5b505af1158015611c5a573d6000803e3d6000fd5b50505050611c887f000000000000000000000000000000000000000000000000000000000000000083612240565b8315611cf157611cf16002805480602002602001604051908101604052809291908181526020018280548015611ce757602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611cc9575b50505050506122f6565b336001600160a01b03167f92ccf450a286a957af52509bc1c9939d1a6a481783e142e41e2499f0bb66ebc68484604051610b20929190612f4e565b600760209081526000928352604080842090915290825290205481565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b031614611d8d57600854611d91565b6009545b9050610d0883826125b6565b611da56122f2565b6000546001600160a01b03908116911614611e07576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6001600160a01b038116611e4c5760405162461bcd60e51b8152600401808060200182810382526026815260200180612fd26026913960400191505060405180910390fd5b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a36000805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b60046020526000908152604090205460ff1681565b600082820183811015610d08576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6000610d0883836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506126bc565b6000610d0883836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250612753565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03811660009081526003602052604081206009548290611ff09085906125b6565b60038301819055905061200284610ce0565b60028301556001600160a01b0385163014612090576001600160a01b0385166000908152600a602052604090206002015461204190869086908461264d565b6001600160a01b038087166000818152600760209081526040808320948a168084529482528083209590955582825260068152848220938252928352838120859055908152600a909152205492505b60085460025460015b8181101561215d57600281815481106120ae57fe5b60009182526020808320909101546001600160a01b03168083526003909152604090912090975094506120e187846125b6565b6003860181905593506120f387610ce0565b60028601556001600160a01b0388163014612155576121148888888761264d565b6001600160a01b03808a166000818152600760209081526040808320948d168084529482528083209590955591815260068252838120928152919052208490555b600101612099565b5050505050505050565b600082612176575060006114fb565b8282028284828161218357fe5b0414610d085760405162461bcd60e51b8152600401808060200182810382526021815260200180612ff86021913960400191505060405180910390fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526117b39084906127b8565b6001600160a01b0382166000908152600360205260409020805442106122805761227662093a806105ba8464e8d4a51000612167565b60018201556122d7565b805460009061228f9042611f23565b905060006122b364e8d4a510006105ba85600101548561216790919063ffffffff16565b90506122cf62093a806105ba64e8d4a510006113068886611ec9565b600184015550505b42600282018190556122ec9062093a80611ec9565b90555050565b3390565b805160005b818110156117b357600083828151811061231157fe5b6020908102919091018101513360009081526007835260408082206001600160a01b0384168352909352918220549092506123519064e8d4a51000611f65565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614612495576001600160a01b03821660009081526003602052604090208054806123c35760405162461bcd60e51b81526004016107aa90612ee5565b60048201546123d5426207e900611ec9565b82101561247f57600061245e82876001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161240e9190612c8b565b60206040518083038186803b15801561242657600080fd5b505afa15801561243a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105e09190612c0a565b9050801561247d576124708682612240565b61247a8282611ec9565b91505b505b6124898185611f23565b83600401819055505050505b806124a1575050612520565b3360008181526007602090815260408083206001600160a01b03871680855292528220919091556124d291836121c0565b816001600160a01b0316336001600160a01b03167f540798df468d7b23d11f156fdb954cb19ad414d150722a7b6d55ba369dea792e836040516125159190612f1c565b60405180910390a350505b6001016122fb565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd000000000000000000000000000000000000000000000000000000001790526125b09085906127b8565b50505050565b6000816125e057506001600160a01b038216600090815260036020819052604090912001546114fb565b6001600160a01b03831660009081526003602052604090206001810154600290910154610d089161262a9185916105ba91670de0b6b3a7640000916113069182906105e08c610ce0565b6001600160a01b0385166000908152600360208190526040909120015490611ec9565b6001600160a01b0380851660008181526007602090815260408083209488168084529482528083205493835260068252808320948352939052918220546126b3919061130c90670de0b6b3a7640000906105ba906126ac908890611f23565b8890612167565b95945050505050565b6000818484111561274b5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156127105781810151838201526020016126f8565b50505050905090810190601f16801561273d5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b600081836127a25760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156127105781810151838201526020016126f8565b5060008385816127ae57fe5b0495945050505050565b6127ca826001600160a01b031661298d565b61281b576040805162461bcd60e51b815260206004820152601f60248201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400604482015290519081900360640190fd5b600080836001600160a01b0316836040518082805190602001908083835b6020831061287657805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101612839565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146128d8576040519150601f19603f3d011682016040523d82523d6000602084013e6128dd565b606091505b509150915081612934576040805162461bcd60e51b815260206004820181905260248201527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604482015290519081900360640190fd5b8051156125b05780806020019051602081101561295057600080fd5b50516125b05760405162461bcd60e51b815260040180806020018281038252602a815260200180613019602a913960400191505060405180910390fd5b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4708181148015906129c157508115155b949350505050565b604051806040016040528060008152602001600081525090565b5080546000825560020290600052602060002090810190610e689190612a1b565b604080518082019091526000808252602082015290565b5b80821115612a365760008082556001820155600201612a1c565b5090565b8035610cdb81612fae565b600060208284031215612a56578081fd5b8135610d0881612fae565b60008060408385031215612a73578081fd5b8235612a7e81612fae565b91506020830135612a8e81612fae565b809150509250929050565b60008060408385031215612aab578182fd5b8235612ab681612fae565b946020939093013593505050565b600080600060608486031215612ad8578081fd5b8335612ae381612fae565b9250602084013591506040840135612afa81612fc3565b809150509250925092565b60006020808385031215612b17578182fd5b823567ffffffffffffffff80821115612b2e578384fd5b818501915085601f830112612b41578384fd5b813581811115612b4d57fe5b83810260405185828201018181108582111715612b6657fe5b604052828152858101935084860182860187018a1015612b84578788fd5b8795505b83861015612bad57612b9981612a3a565b855260019590950194938601938601612b88565b5098975050505050505050565b600060208284031215612bcb578081fd5b8135610d0881612fc3565b600060208284031215612be7578081fd5b8151610d0881612fc3565b600060208284031215612c03578081fd5b5035919050565b600060208284031215612c1b578081fd5b5051919050565b60008060408385031215612c34578182fd5b823591506020830135612a8e81612fc3565b6000815180845260208085019450808401835b83811015612c80578151805188528301518388015260409096019590820190600101612c59565b509495945050505050565b6001600160a01b0391909116815260200190565b6000604082016001600160a01b03808616845260206040818601528286518085526060870191508288019450855b81811015612ceb578551851683529483019491830191600101612ccd565b509098975050505050505050565b6001600160a01b03929092168252602082015260400190565b602080825282518282018190526000919060409081850190868401855b82811015612d5d57815180516001600160a01b03168552860151868501529284019290850190600101612d2f565b5091979650505050505050565b901515815260200190565b6020808252600e908201527f43616e6e6f74207374616b652030000000000000000000000000000000000000604082015260600190565b60208082526022908201527f496e73756666696369656e742062616c616e63652061667465722070656e616c60408201527f7479000000000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526011908201527f43616e6e6f742077697468647261772030000000000000000000000000000000604082015260600190565b6020808252601d908201527f43616e6e6f74207769746864726177207374616b696e6720746f6b656e000000604082015260600190565b6020808252601d908201527f496e73756666696369656e7420756e6c6f636b65642062616c616e6365000000604082015260600190565b6020808252601c908201527f43616e6e6f742077697468647261772072657761726420746f6b656e00000000604082015260600190565b60208082526014908201527f556e6b6e6f776e2072657761726420746f6b656e000000000000000000000000604082015260600190565b90815260200190565b6000838252604060208301526129c16040830184612c46565b9182521515602082015260400190565b918252602082015260400190565b600085825284602083015283604083015260806060830152612f816080830184612c46565b9695505050505050565b948552602085019390935260408401919091526060830152608082015260a00190565b6001600160a01b0381168114610e6857600080fd5b8015158114610e6857600080fdfe4f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f775361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564a26469706673582212200c1f4383aff3ef2c725159fc35400f10b1c0fa628f08370d30be54672e2e201564736f6c63430007060033000000000000000000000000f3e4e939939fa0040b8ceb6efa7c0bf0039dc781
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106102265760003560e01c80638da5cb5b1161012a578063d1a1beb4116100bd578063e6c91a151161008c578063f122977711610071578063f122977714610486578063f2fde38b14610499578063f46eccc4146104ac57610226565b8063e6c91a1514610460578063e70b9e271461047357610226565b8063d1a1beb4146103f9578063dc01f60d1461040c578063df3798761461042c578063e655dbd81461044d57610226565b8063abe50f19116100f9578063abe50f19146103c3578063af1df255146103d6578063bcd11014146103de578063ca5c7b91146103f157610226565b80638da5cb5b1461038b5780638fd9f2ca146103935780639c9b2e21146103a8578063a01c77bc146103bb57610226565b80635e0fac2e116101bd578063715018a61161018c5780637bb7bed1116101715780637bb7bed1146103525780637fd7d062146103655780638980f11f1461037857610226565b8063715018a61461033557806372f702f31461033d57610226565b80635e0fac2e146102e9578063638634ee146102fc5780636eacd3981461030f5780637035ab981461032257610226565b80632e1a7d4d116101f95780632e1a7d4d14610295578063386a9525146102aa57806348e5d9f8146102b2578063547d0096146102d657610226565b806302b629381461022b57806304554443146102555780630483a7f61461026a57806318160ddd1461028d575b600080fd5b61023e610239366004612a45565b6104bf565b60405161024c929190612f4e565b60405180910390f35b61025d6105ef565b60405161024c9190612f1c565b61027d610278366004612a45565b6105f6565b60405161024c9493929190612f5c565b61025d610784565b6102a86102a3366004612bf2565b61078a565b005b61025d610b2e565b6102c56102c0366004612a45565b610b35565b60405161024c959493929190612f8b565b6102a86102e4366004612b05565b610b65565b61025d6102f7366004612a45565b610c48565b61025d61030a366004612a45565b610ce0565b61025d61031d366004612a45565b610d0f565b61025d610330366004612a61565b610d2a565b6102a8610d47565b610345610e08565b60405161024c9190612c8b565b610345610360366004612bf2565b610e2c565b6102a8610373366004612b05565b610e56565b6102a8610386366004612a99565b610e6b565b610345610fb9565b61039b610fc8565b60405161024c9190612d6a565b6102a86103b6366004612a45565b610fd1565b6102a86110d0565b6102a86103d1366004612c22565b61126c565b6103456114b8565b61025d6103ec366004612a45565b6114c7565b61025d611501565b6102a8610407366004612ac4565b611507565b61041f61041a366004612a45565b6117b8565b60405161024c9190612d12565b61043f61043a366004612a45565b611953565b60405161024c929190612f25565b6102a861045b366004612a45565b611a77565b6102a861046e366004612bba565b611b10565b61025d610481366004612a61565b611d2c565b61025d610494366004612a45565b611d49565b6102a86104a7366004612a45565b611d9d565b61039b6104ba366004612a45565b611eb4565b6001600160a01b0381166000908152600a60205260408120600381015482919080156105c5576001600160a01b0385166000908152600c6020526040812054815b818110156105aa576001600160a01b0388166000908152600c6020526040812080548390811061052c57fe5b9060005260206000209060020201600001549050806000141561054f57506105a2565b6001600160a01b0389166000908152600c6020526040902080544291908490811061057657fe5b906000526020600020906002020160010154111561059457506105aa565b61059e8482611ec9565b9350505b600101610500565b506105c060026105ba8585611f23565b90611f65565b945050505b6105e6836105e0838560010154611ec990919063ffffffff16565b90611f23565b93505050915091565b6277f88081565b6001600160a01b0381166000908152600b602052604081208190819060609082805b825481101561075c574283828154811061062e57fe5b906000526020600020906002020160010154111561072a57816106a457825481900367ffffffffffffffff8111801561066657600080fd5b506040519080825280602002602001820160405280156106a057816020015b61068d6129c9565b8152602001906001900390816106855790505b5093505b8281815481106106b057fe5b9060005260206000209060020201604051806040016040529081600082015481526020016001820154815250508483815181106106e957fe5b6020026020010181905250818060010192505061072383828154811061070b57fe5b60009182526020909120600290910201548690611ec9565b9450610754565b61075183828154811061073957fe5b60009182526020909120600290910201548790611ec9565b95505b600101610618565b5050506001600160a01b0385166000908152600a602052604090206002015493509193509193565b60085481565b600081116107b35760405162461bcd60e51b81526004016107aa90612e09565b60405180910390fd5b6107bc33611fa7565b336000908152600a60205260408120600181015490919083116107f25760018201546107e89084611f23565b60018301556109c7565b600061080b836001015485611f2390919063ffffffff16565b905080836003015410156108315760405162461bcd60e51b81526004016107aa90612e77565b6000600184015560038301546108479082611f23565b600384015560005b336000908152600c6020526040812080548390811061086a57fe5b9060005260206000209060020201600001549050806000141561088d57506109bc565b831580156108c85750336000908152600c602052604090208054429190849081106108b457fe5b906000526020600020906002020160010154115b1561093a5782935082856003015410156108f45760405162461bcd60e51b81526004016107aa90612dac565b60038501546109039084611f23565b6003860181905561092c57336000908152600c60205260408120610926916129e3565b506109c4565b610937836002612167565b92505b80831161097d5761094b8184611f23565b336000908152600c6020526040902080548490811061096657fe5b6000918252602090912060029091020155506109c4565b336000908152600c6020526040902080548390811061099857fe5b600091825260208220600290910201818155600101556109b88382611f23565b9250505b60010161084f565b50505b60006109d38483611ec9565b83549091506109e29082611f23565b83556008546109f19082611f23565b600855610a286001600160a01b037f000000000000000000000000f3e4e939939fa0040b8ceb6efa7c0bf0039dc7811633866121c0565b8115610ae5576001546001600160a01b0316638e2eba09306000604051908082528060200260200182016040528015610a6b578160200160208202803683370190505b506040518363ffffffff1660e01b8152600401610a89929190612c9f565b600060405180830381600087803b158015610aa357600080fd5b505af1158015610ab7573d6000803e3d6000fd5b50505050610ae57f000000000000000000000000f3e4e939939fa0040b8ceb6efa7c0bf0039dc78183612240565b336001600160a01b03167f92ccf450a286a957af52509bc1c9939d1a6a481783e142e41e2499f0bb66ebc68584604051610b20929190612f4e565b60405180910390a250505050565b62093a8081565b60036020819052600091825260409091208054600182015460028301549383015460049093015491939092909185565b610b6d6122f2565b6000546001600160a01b03908116911614610bcf576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b60055460ff1615610bdf57600080fd5b60005b8151811015610c3757600160046000848481518110610bfd57fe5b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff1916911515919091179055600101610be2565b50506005805460ff19166001179055565b6001600160a01b0381166000908152600a6020908152604080832060010154338452600c909252822090915b8154811015610cd85742828281548110610c8a57fe5b9060005260206000209060020201600101541115610ca757610cd8565b610cce828281548110610cb657fe5b60009182526020909120600290910201548490611ec9565b9250600101610c74565b50505b919050565b6001600160a01b038116600090815260036020526040812054428111610d065780610d08565b425b9392505050565b6001600160a01b03166000908152600a602052604090205490565b600660209081526000928352604080842090915290825290205481565b610d4f6122f2565b6000546001600160a01b03908116911614610db1576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a36000805473ffffffffffffffffffffffffffffffffffffffff19169055565b7f000000000000000000000000f3e4e939939fa0040b8ceb6efa7c0bf0039dc78181565b60028181548110610e3c57600080fd5b6000918252602090912001546001600160a01b0316905081565b610e5f33611fa7565b610e68816122f6565b50565b610e736122f2565b6000546001600160a01b03908116911614610ed5576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b7f000000000000000000000000f3e4e939939fa0040b8ceb6efa7c0bf0039dc7816001600160a01b0316826001600160a01b03161415610f275760405162461bcd60e51b81526004016107aa90612e40565b6001600160a01b03821660009081526003602052604090206002015415610f605760405162461bcd60e51b81526004016107aa90612eae565b610f7c610f6b610fb9565b6001600160a01b03841690836121c0565b7f8c1256b8896378cd5044f80c202f9772b9d77dc85c8a6eb51967210b09bfaa288282604051610fad929190612cf9565b60405180910390a15050565b6000546001600160a01b031690565b60055460ff1681565b610fd96122f2565b6000546001600160a01b0390811691161461103b576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6001600160a01b0381166000908152600360205260409020600201541561106157600080fd5b600280546001810182557f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace0180546001600160a01b0390931673ffffffffffffffffffffffffffffffffffffffff19909316831790556000918252600360205260409091204291810182905555565b6110d933611fa7565b336000908152600b60209081526040808320600a90925282208154919290914284600019830183811061110857fe5b90600052602060002090600202016001015411611145576002830154336000908152600b6020526040812091935061114091906129e3565b6111ba565b60005b818110156111b8574285828154811061115d57fe5b906000526020600020906002020160010154111561117a576111b8565b611189858281548110610cb657fe5b925084818154811061119757fe5b60009182526020822060029091020181815560019081019190915501611148565b505b60028301546111c99083611f23565b600284015582546111da9083611f23565b83556008546111e99083611f23565b6008556009546111f99083611f23565b6009556112306001600160a01b037f000000000000000000000000f3e4e939939fa0040b8ceb6efa7c0bf0039dc7811633846121c0565b336001600160a01b03167f92ccf450a286a957af52509bc1c9939d1a6a481783e142e41e2499f0bb66ebc6836000604051610b20929190612f4e565b6000821161128c5760405162461bcd60e51b81526004016107aa90612d75565b61129533611fa7565b6008546112a29083611ec9565b600855336000908152600a6020526040902080546112c09084611ec9565b81558115611426576009546112d59084611ec9565b60095560028101546112e79084611ec9565b600282015560006113126277f88061130c62093a806113064282611f65565b90612167565b90611ec9565b336000908152600b60205260409020549091508015806113635750336000908152600b602052604090208054839190600019840190811061134f57fe5b906000526020600020906002020160010154105b156113b257336000908152600b6020908152604080832081518083019092528882528183018681528154600181810184559286529390942091516002909302909101918255915191015561141f565b336000908152600b6020526040902080546113ee91879160001985019081106113d757fe5b600091825260209091206002909102015490611ec9565b336000908152600b602052604090208054600019840190811061140d57fe5b60009182526020909120600290910201555b505061143b565b60018101546114359084611ec9565b60018201555b6114706001600160a01b037f000000000000000000000000f3e4e939939fa0040b8ceb6efa7c0bf0039dc78116333086612528565b336001600160a01b03167f37d4053e34fde482e96f6bcd424dfa31342cbd5fe184d497fb3c8bb4b4b9758084846040516114ab929190612f3e565b60405180910390a2505050565b6001546001600160a01b031681565b6001600160a01b0381166000908152600360205260408120600101546114fb9064e8d4a51000906105ba9062093a80612167565b92915050565b60095481565b3360009081526004602052604090205460ff1661152357600080fd5b8161152d576117b3565b61153683611fa7565b6040517f40c10f190000000000000000000000000000000000000000000000000000000081526001600160a01b037f000000000000000000000000f3e4e939939fa0040b8ceb6efa7c0bf0039dc78116906340c10f199061159d9030908690600401612cf9565b602060405180830381600087803b1580156115b757600080fd5b505af11580156115cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115ef9190612bd6565b506001600160a01b0383163014156116305761162b7f000000000000000000000000f3e4e939939fa0040b8ceb6efa7c0bf0039dc78183612240565b6117b3565b60085461163d9083611ec9565b6008556001600160a01b0383166000908152600a6020526040902080546116649084611ec9565b8155811561176257600381015461167b9084611ec9565b6003820155600061169a6277f88061130c62093a806113064282611f65565b6001600160a01b0386166000908152600c602052604090208054919250908015806116e45750828260018303815481106116d057fe5b906000526020600020906002020160010154105b1561172657604080518082019091528681526020808201858152845460018181018755600087815293909320935160029091029093019283555191015561175a565b611739868360018403815481106113d757fe5b82600183038154811061174857fe5b60009182526020909120600290910201555b505050611777565b60018101546117719084611ec9565b60018201555b836001600160a01b03167f37d4053e34fde482e96f6bcd424dfa31342cbd5fe184d497fb3c8bb4b4b97580846000604051610b20929190612f3e565b505050565b60025460609067ffffffffffffffff811180156117d457600080fd5b5060405190808252806020026020018201604052801561180e57816020015b6117fb612a04565b8152602001906001900390816117f35790505b50905060005b815181101561194d5760008115611843576001600160a01b0384166000908152600a6020526040902054611860565b6001600160a01b0384166000908152600a60205260409020600201545b90506000821561187257600854611876565b6009545b90506002838154811061188557fe5b9060005260206000200160009054906101000a90046001600160a01b03168484815181106118af57fe5b6020026020010151600001906001600160a01b031690816001600160a01b03168152505061192964e8d4a510006105ba878787815181106118ec57fe5b6020026020010151600001518661192460028a8154811061190957fe5b6000918252602090912001546001600160a01b0316886125b6565b61264d565b84848151811061193557fe5b60209081029190910181015101525050600101611814565b50919050565b6001600160a01b0381166000908152600c6020526040812060609082805b8254811015611a6f574283828154811061198757fe5b9060005260206000209060020201600101541115611a6757816119fd57825481900367ffffffffffffffff811180156119bf57600080fd5b506040519080825280602002602001820160405280156119f957816020015b6119e66129c9565b8152602001906001900390816119de5790505b5093505b828181548110611a0957fe5b906000526020600020906002020160405180604001604052908160008201548152602001600182015481525050848381518110611a4257fe5b60200260200101819052508180600101925050611a6483828154811061070b57fe5b94505b600101611971565b505050915091565b611a7f6122f2565b6000546001600160a01b03908116911614611ae1576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6001805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b611b1933611fa7565b600080611b25336104bf565b336000908152600c60205260408120929450909250611b4491906129e3565b336000908152600a60205260409020600381015460018201548254611b6e92916105e09190611f23565b81556000600182018190556003820155611b94611b8b8484611ec9565b60085490611f23565b600855611bcb6001600160a01b037f000000000000000000000000f3e4e939939fa0040b8ceb6efa7c0bf0039dc7811633856121c0565b8115611c88576001546001600160a01b0316638e2eba09306000604051908082528060200260200182016040528015611c0e578160200160208202803683370190505b506040518363ffffffff1660e01b8152600401611c2c929190612c9f565b600060405180830381600087803b158015611c4657600080fd5b505af1158015611c5a573d6000803e3d6000fd5b50505050611c887f000000000000000000000000f3e4e939939fa0040b8ceb6efa7c0bf0039dc78183612240565b8315611cf157611cf16002805480602002602001604051908101604052809291908181526020018280548015611ce757602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611cc9575b50505050506122f6565b336001600160a01b03167f92ccf450a286a957af52509bc1c9939d1a6a481783e142e41e2499f0bb66ebc68484604051610b20929190612f4e565b600760209081526000928352604080842090915290825290205481565b6000807f000000000000000000000000f3e4e939939fa0040b8ceb6efa7c0bf0039dc7816001600160a01b0316836001600160a01b031614611d8d57600854611d91565b6009545b9050610d0883826125b6565b611da56122f2565b6000546001600160a01b03908116911614611e07576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6001600160a01b038116611e4c5760405162461bcd60e51b8152600401808060200182810382526026815260200180612fd26026913960400191505060405180910390fd5b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a36000805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b60046020526000908152604090205460ff1681565b600082820183811015610d08576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6000610d0883836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506126bc565b6000610d0883836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250612753565b7f000000000000000000000000f3e4e939939fa0040b8ceb6efa7c0bf0039dc7816001600160a01b03811660009081526003602052604081206009548290611ff09085906125b6565b60038301819055905061200284610ce0565b60028301556001600160a01b0385163014612090576001600160a01b0385166000908152600a602052604090206002015461204190869086908461264d565b6001600160a01b038087166000818152600760209081526040808320948a168084529482528083209590955582825260068152848220938252928352838120859055908152600a909152205492505b60085460025460015b8181101561215d57600281815481106120ae57fe5b60009182526020808320909101546001600160a01b03168083526003909152604090912090975094506120e187846125b6565b6003860181905593506120f387610ce0565b60028601556001600160a01b0388163014612155576121148888888761264d565b6001600160a01b03808a166000818152600760209081526040808320948d168084529482528083209590955591815260068252838120928152919052208490555b600101612099565b5050505050505050565b600082612176575060006114fb565b8282028284828161218357fe5b0414610d085760405162461bcd60e51b8152600401808060200182810382526021815260200180612ff86021913960400191505060405180910390fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526117b39084906127b8565b6001600160a01b0382166000908152600360205260409020805442106122805761227662093a806105ba8464e8d4a51000612167565b60018201556122d7565b805460009061228f9042611f23565b905060006122b364e8d4a510006105ba85600101548561216790919063ffffffff16565b90506122cf62093a806105ba64e8d4a510006113068886611ec9565b600184015550505b42600282018190556122ec9062093a80611ec9565b90555050565b3390565b805160005b818110156117b357600083828151811061231157fe5b6020908102919091018101513360009081526007835260408082206001600160a01b0384168352909352918220549092506123519064e8d4a51000611f65565b90507f000000000000000000000000f3e4e939939fa0040b8ceb6efa7c0bf0039dc7816001600160a01b0316826001600160a01b031614612495576001600160a01b03821660009081526003602052604090208054806123c35760405162461bcd60e51b81526004016107aa90612ee5565b60048201546123d5426207e900611ec9565b82101561247f57600061245e82876001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161240e9190612c8b565b60206040518083038186803b15801561242657600080fd5b505afa15801561243a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105e09190612c0a565b9050801561247d576124708682612240565b61247a8282611ec9565b91505b505b6124898185611f23565b83600401819055505050505b806124a1575050612520565b3360008181526007602090815260408083206001600160a01b03871680855292528220919091556124d291836121c0565b816001600160a01b0316336001600160a01b03167f540798df468d7b23d11f156fdb954cb19ad414d150722a7b6d55ba369dea792e836040516125159190612f1c565b60405180910390a350505b6001016122fb565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd000000000000000000000000000000000000000000000000000000001790526125b09085906127b8565b50505050565b6000816125e057506001600160a01b038216600090815260036020819052604090912001546114fb565b6001600160a01b03831660009081526003602052604090206001810154600290910154610d089161262a9185916105ba91670de0b6b3a7640000916113069182906105e08c610ce0565b6001600160a01b0385166000908152600360208190526040909120015490611ec9565b6001600160a01b0380851660008181526007602090815260408083209488168084529482528083205493835260068252808320948352939052918220546126b3919061130c90670de0b6b3a7640000906105ba906126ac908890611f23565b8890612167565b95945050505050565b6000818484111561274b5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156127105781810151838201526020016126f8565b50505050905090810190601f16801561273d5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b600081836127a25760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156127105781810151838201526020016126f8565b5060008385816127ae57fe5b0495945050505050565b6127ca826001600160a01b031661298d565b61281b576040805162461bcd60e51b815260206004820152601f60248201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400604482015290519081900360640190fd5b600080836001600160a01b0316836040518082805190602001908083835b6020831061287657805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101612839565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146128d8576040519150601f19603f3d011682016040523d82523d6000602084013e6128dd565b606091505b509150915081612934576040805162461bcd60e51b815260206004820181905260248201527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604482015290519081900360640190fd5b8051156125b05780806020019051602081101561295057600080fd5b50516125b05760405162461bcd60e51b815260040180806020018281038252602a815260200180613019602a913960400191505060405180910390fd5b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4708181148015906129c157508115155b949350505050565b604051806040016040528060008152602001600081525090565b5080546000825560020290600052602060002090810190610e689190612a1b565b604080518082019091526000808252602082015290565b5b80821115612a365760008082556001820155600201612a1c565b5090565b8035610cdb81612fae565b600060208284031215612a56578081fd5b8135610d0881612fae565b60008060408385031215612a73578081fd5b8235612a7e81612fae565b91506020830135612a8e81612fae565b809150509250929050565b60008060408385031215612aab578182fd5b8235612ab681612fae565b946020939093013593505050565b600080600060608486031215612ad8578081fd5b8335612ae381612fae565b9250602084013591506040840135612afa81612fc3565b809150509250925092565b60006020808385031215612b17578182fd5b823567ffffffffffffffff80821115612b2e578384fd5b818501915085601f830112612b41578384fd5b813581811115612b4d57fe5b83810260405185828201018181108582111715612b6657fe5b604052828152858101935084860182860187018a1015612b84578788fd5b8795505b83861015612bad57612b9981612a3a565b855260019590950194938601938601612b88565b5098975050505050505050565b600060208284031215612bcb578081fd5b8135610d0881612fc3565b600060208284031215612be7578081fd5b8151610d0881612fc3565b600060208284031215612c03578081fd5b5035919050565b600060208284031215612c1b578081fd5b5051919050565b60008060408385031215612c34578182fd5b823591506020830135612a8e81612fc3565b6000815180845260208085019450808401835b83811015612c80578151805188528301518388015260409096019590820190600101612c59565b509495945050505050565b6001600160a01b0391909116815260200190565b6000604082016001600160a01b03808616845260206040818601528286518085526060870191508288019450855b81811015612ceb578551851683529483019491830191600101612ccd565b509098975050505050505050565b6001600160a01b03929092168252602082015260400190565b602080825282518282018190526000919060409081850190868401855b82811015612d5d57815180516001600160a01b03168552860151868501529284019290850190600101612d2f565b5091979650505050505050565b901515815260200190565b6020808252600e908201527f43616e6e6f74207374616b652030000000000000000000000000000000000000604082015260600190565b60208082526022908201527f496e73756666696369656e742062616c616e63652061667465722070656e616c60408201527f7479000000000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526011908201527f43616e6e6f742077697468647261772030000000000000000000000000000000604082015260600190565b6020808252601d908201527f43616e6e6f74207769746864726177207374616b696e6720746f6b656e000000604082015260600190565b6020808252601d908201527f496e73756666696369656e7420756e6c6f636b65642062616c616e6365000000604082015260600190565b6020808252601c908201527f43616e6e6f742077697468647261772072657761726420746f6b656e00000000604082015260600190565b60208082526014908201527f556e6b6e6f776e2072657761726420746f6b656e000000000000000000000000604082015260600190565b90815260200190565b6000838252604060208301526129c16040830184612c46565b9182521515602082015260400190565b918252602082015260400190565b600085825284602083015283604083015260806060830152612f816080830184612c46565b9695505050505050565b948552602085019390935260408401919091526060830152608082015260a00190565b6001600160a01b0381168114610e6857600080fd5b8015158114610e6857600080fdfe4f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f775361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564a26469706673582212200c1f4383aff3ef2c725159fc35400f10b1c0fa628f08370d30be54672e2e201564736f6c63430007060033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000f3e4e939939fa0040b8ceb6efa7c0bf0039dc781
-----Decoded View---------------
Arg [0] : _stakingToken (address): 0xF3e4E939939fa0040b8ceb6Efa7c0BF0039dc781
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000f3e4e939939fa0040b8ceb6efa7c0bf0039dc781
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.