Polygon Sponsored slots available. Book your slot here!
Contract Overview
My Name Tag:
Not Available, login to update
[ Download CSV Export ]
Contract Name:
ERC20RewardPool
Compiler Version
v0.8.2+commit.661d1103
Optimization Enabled:
Yes with 2000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
//SPDX-License-Identifier: MIT pragma solidity 0.8.2; import {Context} from "@openzeppelin/contracts-0.8/utils/Context.sol"; import {SafeERC20} from "@openzeppelin/contracts-0.8/token/ERC20/utils/SafeERC20.sol"; import {IERC20} from "@openzeppelin/contracts-0.8/token/ERC20/IERC20.sol"; import {ReentrancyGuard} from "@openzeppelin/contracts-0.8/security/ReentrancyGuard.sol"; import {Address} from "@openzeppelin/contracts-0.8/utils/Address.sol"; import {Pausable} from "@openzeppelin/contracts-0.8/security/Pausable.sol"; import {Ownable} from "@openzeppelin/contracts-0.8/access/Ownable.sol"; import {Math} from "@openzeppelin/contracts-0.8/utils/math/Math.sol"; import {ERC2771HandlerV2} from "../common/BaseWithStorage/ERC2771HandlerV2.sol"; import {StakeTokenWrapper} from "./StakeTokenWrapper.sol"; import {IContributionRules} from "./interfaces/IContributionRules.sol"; import {IRewardCalculator} from "./interfaces/IRewardCalculator.sol"; import {LockRules} from "./rules/LockRules.sol"; import {RequirementsRules} from "./rules/RequirementsRules.sol"; /// @title A pool that distributes rewards between users that stake any erc20 token /// @notice The contributions are updated passively, an external call to computeContribution from a backend is needed. /// @notice After initialization the reward calculator must be set by the admin. /// @dev The contract has two plugins that affect the behaviour: contributionCalculator and rewardCalculator /// @dev contributionCalculator instead of using the stake directly the result of computeContribution is used /// @dev this way some users can get an extra share of the rewards /// @dev rewardCalculator is used to manage the rate at which the rewards are distributed. /// @dev This way we can build different types of pools by mixing in the plugins we want with this contract. /// @dev default behaviour (address(0)) for contributionCalculator is to use the stacked amount as contribution. /// @dev default behaviour (address(0)) for rewardCalculator is that no rewards are given contract ERC20RewardPool is Ownable, StakeTokenWrapper, LockRules, RequirementsRules, ReentrancyGuard, ERC2771HandlerV2, Pausable { using SafeERC20 for IERC20; using Address for address; event Staked(address indexed account, uint256 stakeAmount); event Withdrawn(address indexed account, uint256 stakeAmount); event Exit(address indexed account); event RewardPaid(address indexed account, uint256 rewardAmount); event ContributionUpdated(address indexed account, uint256 newContribution, uint256 oldContribution); uint256 internal constant DECIMALS_18 = 1 ether; // This value multiplied by the user contribution is the share of accumulated rewards (from the start of time // until the last call to restartRewards) for the user taking into account the value of totalContributions. uint256 public rewardPerTokenStored; IERC20 public rewardToken; IContributionRules public contributionRules; IRewardCalculator public rewardCalculator; // This value multiplied by the user contribution is the share of reward from the the last time // the user changed his contribution and called restartRewards mapping(address => uint256) public userRewardPerTokenPaid; // This value is the accumulated rewards won by the user when he called the contract. mapping(address => uint256) public rewards; uint256 internal _totalContributions; mapping(address => uint256) internal _contributions; constructor( IERC20 stakeToken_, IERC20 rewardToken_, address trustedForwarder ) StakeTokenWrapper(stakeToken_) { require(address(rewardToken_).isContract(), "ERC20RewardPool: is not a contract"); rewardToken = rewardToken_; __ERC2771HandlerV2_initialize(trustedForwarder); } // Checks that the given address is a contract and // that the caller of the method is the owner of this contract - ERC20RewardPool. modifier isContractAndAdmin(address contractAddress) { require(contractAddress.isContract(), "ERC20RewardPool: is not a contract"); require(owner() == _msgSender(), "ERC20RewardPool: not admin"); _; } modifier isValidAddress(address account) { require(account != address(0), "ERC20RewardPool: zero address"); _; } /// @notice set the reward token /// @param contractAddress address token used to pay rewards function setRewardToken(address contractAddress) external isContractAndAdmin(contractAddress) isValidAddress(contractAddress) { IERC20 _newRewardToken = IERC20(contractAddress); require( rewardToken.balanceOf(address(this)) <= _newRewardToken.balanceOf(address(this)), "ERC20RewardPool: insufficient balance" ); rewardToken = _newRewardToken; } /// @notice set the stake token /// @param contractAddress address token used to stake funds function setStakeToken(address contractAddress) external isContractAndAdmin(contractAddress) isValidAddress(contractAddress) { IERC20 _newStakeToken = IERC20(contractAddress); require( _stakeToken.balanceOf(address(this)) <= _newStakeToken.balanceOf(address(this)), "ERC20RewardPool: insufficient balance" ); _stakeToken = _newStakeToken; } /// @notice set the trusted forwarder /// @param trustedForwarder address of the contract that is enabled to send meta-tx on behalf of the user function setTrustedForwarder(address trustedForwarder) external isContractAndAdmin(trustedForwarder) { _trustedForwarder = trustedForwarder; } /// @notice set contract that contains all the contribution rules function setContributionRules(address contractAddress) external isContractAndAdmin(contractAddress) isValidAddress(contractAddress) { contributionRules = IContributionRules(contractAddress); } /// @notice set the reward calculator /// @param contractAddress address of a plugin that calculates absolute rewards at any point in time /// @param restartRewards_ if true the rewards from the previous calculator are accumulated before changing it function setRewardCalculator(address contractAddress, bool restartRewards_) external isContractAndAdmin(contractAddress) isValidAddress(contractAddress) { // We process the rewards of the current reward calculator before the switch. if (restartRewards_) { _restartRewards(); } rewardCalculator = IRewardCalculator(contractAddress); } /// @notice the admin recover is able to recover reward funds /// @param receiver address of the beneficiary of the recovered funds /// @dev this function must be called in an emergency situation only. /// @dev Calling it is risky specially when rewardToken == stakeToken function recoverFunds(address receiver) external onlyOwner whenPaused() isValidAddress(receiver) { uint256 recoverAmount; if (rewardToken == _stakeToken) { recoverAmount = rewardToken.balanceOf(address(this)) - _totalSupply; } else { recoverAmount = rewardToken.balanceOf(address(this)); } rewardToken.safeTransfer(receiver, recoverAmount); } /// @notice return the total supply of staked tokens /// @return the total supply of staked tokens function totalSupply() external view returns (uint256) { return _totalSupply; } /// @notice return the balance of staked tokens for a user /// @param account the address of the account /// @return balance of staked tokens function balanceOf(address account) external view returns (uint256) { return _balances[account]; } /// @notice return the address of the stake token contract /// @return address of the stake token contract function stakeToken() external view returns (IERC20) { return _stakeToken; } /// @notice return the amount of rewards deposited in the contract that can be distributed by different campaigns /// @return the total amount of deposited rewards /// @dev this function can be called by a reward calculator to throw if a campaign doesn't have /// @dev enough rewards to start function getRewardsAvailable() external view returns (uint256) { if (address(rewardToken) != address(_stakeToken)) { return rewardToken.balanceOf(address(this)); } return _stakeToken.balanceOf(address(this)) - _totalSupply; } /// @notice return the sum of the values returned by the contribution calculator /// @return total contributions of the users /// @dev this is the same than the totalSupply only if the contribution calculator /// @dev uses the staked amount as the contribution of the user which is the default behaviour function totalContributions() external view returns (uint256) { return _totalContributions; } /// @notice return the contribution of some user /// @param account the address of the account /// @return contribution of the users /// @dev this is the same than the balanceOf only if the contribution calculator /// @dev uses the staked amount as the contribution of the user which is the default behaviour function contributionOf(address account) external view returns (uint256) { return _contributions[account]; } /// @notice accumulated rewards taking into account the totalContribution (see: rewardPerTokenStored) /// @return the accumulated total rewards /// @dev This value multiplied by the user contribution is the share of accumulated rewards for the user. Taking /// @dev into account the value of totalContributions. function rewardPerToken() external view returns (uint256) { return rewardPerTokenStored + _rewardPerToken(); } /// @notice available earnings for some user /// @param account the address of the account /// @return the available earnings for the user function earned(address account) external view returns (uint256) { return rewards[account] + _earned(account, _rewardPerToken()); } /// @notice accumulates the current rewards into rewardPerTokenStored and restart the reward calculator /// @dev calling this function makes no difference. It is useful for testing and when the reward calculator /// @dev is changed. function restartRewards() external { _restartRewards(); } /// @notice update the contribution for a user /// @param account the address of the account /// @dev if the user change his holdings (or any other parameter that affect the contribution calculation), /// @dev he can the reward distribution to his favor. This function must be called by an external agent ASAP to /// @dev update the contribution for the user. We understand the risk but the rewards are distributed slowly so /// @dev the user cannot affect the reward distribution heavily. function computeContribution(address account) external isValidAddress(account) { // We decide to give the user the accumulated rewards even if he cheated a little bit. _processRewards(account); _updateContribution(account); } /// @notice update the contribution for a sef of users /// @param accounts the addresses of the accounts to update /// @dev see: computeContribution function computeContributionInBatch(address[] calldata accounts) external { _restartRewards(); for (uint256 i = 0; i < accounts.length; i++) { address account = accounts[i]; if (account == address(0)) { continue; } _processAccountRewards(account); _updateContribution(account); } } /// @notice stake some amount into the contract /// @param amount the amount of tokens to stake /// @dev the user must approve in the stake token before calling this function function stake(uint256 amount) external nonReentrant whenNotPaused() antiDepositCheck(_msgSender()) checkRequirements(_msgSender(), amount, _balances[_msgSender()]) { require(amount > 0, "ERC20RewardPool: Cannot stake 0"); // The first time a user stakes he cannot remove his rewards immediately. if (timeLockClaim.lastClaim[_msgSender()] == 0) { timeLockClaim.lastClaim[_msgSender()] = block.timestamp; } lockDeposit.lastDeposit[_msgSender()] = block.timestamp; uint256 earlierRewards = 0; if (_totalContributions == 0 && rewardCalculator != IRewardCalculator(address(0))) { earlierRewards = rewardCalculator.getRewards(); } _processRewards(_msgSender()); super._stake(amount); _updateContribution(_msgSender()); require(_contributions[_msgSender()] > 0, "ERC20RewardPool: not enough contributions"); if (earlierRewards != 0) { rewards[_msgSender()] = rewards[_msgSender()] + earlierRewards; } emit Staked(_msgSender(), amount); } /// @notice withdraw the stake from the contract /// @param amount the amount of tokens to withdraw /// @dev the user can withdraw his stake independently from the rewards function withdraw(uint256 amount) external nonReentrant whenNotPaused() { _processRewards(_msgSender()); _withdrawStake(_msgSender(), amount); _updateContribution(_msgSender()); } /// @notice withdraw the stake and the rewards from the contract function exit() external nonReentrant whenNotPaused() { _processRewards(_msgSender()); _withdrawStake(_msgSender(), _balances[_msgSender()]); _withdrawRewards(_msgSender()); _updateContribution(_msgSender()); emit Exit(_msgSender()); } /// @notice withdraw the rewards from the contract /// @dev the user can withdraw his stake independently from the rewards function getReward() external nonReentrant whenNotPaused() { _processRewards(_msgSender()); _withdrawRewards(_msgSender()); _updateContribution(_msgSender()); } function renounceOwnership() public view override onlyOwner { revert("ERC20RewardPool: can't renounceOwnership"); } function _withdrawStake(address account, uint256 amount) internal antiWithdrawCheck(_msgSender()) { require(amount > 0, "ERC20RewardPool: Cannot withdraw 0"); lockWithdraw.lastWithdraw[_msgSender()] = block.timestamp; super._withdraw(amount); emit Withdrawn(account, amount); } function _withdrawRewards(address account) internal timeLockClaimCheck(account) { uint256 reward = rewards[account]; uint256 mod = 0; if (reward > 0) { if (amountLockClaim.claimLockEnabled == true) { // constrain the reward amount to the integer allowed mod = reward % DECIMALS_18; reward = reward - mod; require( amountLockClaim.amount <= reward, "ERC20RewardPool: Cannot withdraw - lockClaim.amount < reward" ); } rewards[account] = mod; rewardToken.safeTransfer(account, reward); emit RewardPaid(account, reward); } } function _updateContribution(address account) internal { uint256 oldContribution = _contributions[account]; _totalContributions = _totalContributions - oldContribution; uint256 contribution = _computeContribution(account); _totalContributions = _totalContributions + contribution; _contributions[account] = contribution; emit ContributionUpdated(account, contribution, oldContribution); } function _computeContribution(address account) internal returns (uint256) { if (contributionRules == IContributionRules(address(0))) { return Math.min(_balances[account], maxStakeAllowedCalculator(account)); } else { return contributionRules.computeMultiplier( account, Math.min(_balances[account], maxStakeAllowedCalculator(account)) ); } } // Something changed (stake, withdraw, etc), we distribute current accumulated rewards and start from zero. // Called each time there is a change in contract state (stake, withdraw, etc). function _processRewards(address account) internal { _restartRewards(); _processAccountRewards(account); } // Update the earnings for this specific user with what he earned until now function _processAccountRewards(address account) internal { // usually _earned takes _rewardPerToken() but in this method is zero because _restartRewards must be // called before _processAccountRewards rewards[account] = rewards[account] + _earned(account, 0); // restart rewards for this specific user, now earned(account) = 0 userRewardPerTokenPaid[account] = rewardPerTokenStored; } function _restartRewards() internal { if (rewardCalculator != IRewardCalculator(address(0))) { // Distribute the accumulated rewards rewardPerTokenStored = rewardPerTokenStored + _rewardPerToken(); // restart rewards so now the rewardCalculator return zero rewards rewardCalculator.restartRewards(); } } function _earned(address account, uint256 rewardPerToken_) internal view returns (uint256) { // - userRewardPerTokenPaid[account] * _contributions[account] / _totalContributions is the portion of // rewards the last time the user changed his contribution and called _restartRewards // (_totalContributions corresponds to previous value of that moment). // - rewardPerTokenStored * _contributions[account] is the share of the user from the // accumulated rewards (from the start of time until the last call to _restartRewards) with the // current value of _totalContributions // - _rewardPerToken() * _contributions[account] / _totalContributions is the share of the user of the // rewards from the last time anybody called _restartRewards until this moment // // The important thing to note is that at any moment in time _contributions[account] / _totalContributions is // the share of the user even if _totalContributions changes because of other users activity. return ((rewardPerToken_ + rewardPerTokenStored - userRewardPerTokenPaid[account]) * _contributions[account]) / 1e24; } // This function gives the proportion of the total contribution that corresponds to each user from // last restartRewards call. // _rewardsPerToken() * _contributions[account] is the amount of extra rewards gained from last restartRewards. function _rewardPerToken() internal view returns (uint256) { if (rewardCalculator == IRewardCalculator(address(0)) || _totalContributions == 0) { return 0; } return (rewardCalculator.getRewards() * 1e24) / _totalContributions; } // @dev Triggers stopped state. // The contract must not be paused. function pause() external onlyOwner { _pause(); } // @dev Returns to normal state. // The contract must be paused. function unpause() external onlyOwner { _unpause(); } function _msgSender() internal view override(Context, ERC2771HandlerV2) returns (address sender) { return ERC2771HandlerV2._msgSender(); } function _msgData() internal view override(Context, ERC2771HandlerV2) returns (bytes calldata) { return ERC2771HandlerV2._msgData(); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @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 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) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { 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)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove( IERC20 token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @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 // OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor() { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { // On the first call to nonReentrant, _notEntered will be true require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Address.sol) pragma solidity ^0.8.0; /** * @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) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; assembly { size := extcodesize(account) } return size > 0; } /** * @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"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (security/Pausable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract Pausable is Context { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ constructor() { _paused = false; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { require(!paused(), "Pausable: paused"); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { require(paused(), "Pausable: not paused"); _; } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/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. */ abstract 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() { _transferOwnership(_msgSender()); } /** * @dev Returns the address of the current owner. */ function owner() public view virtual 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 { _transferOwnership(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"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a >= b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a / b + (a % b == 0 ? 0 : 1); } }
// SPDX-License-Identifier: MIT // solhint-disable-next-line compiler-version pragma solidity 0.8.2; /// @dev minimal ERC2771 handler to keep bytecode-size down. /// based on: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/metatx/ERC2771Context.sol abstract contract ERC2771HandlerV2 { address internal _trustedForwarder; function __ERC2771HandlerV2_initialize(address forwarder) internal { _trustedForwarder = forwarder; } function isTrustedForwarder(address forwarder) public view returns (bool) { return forwarder == _trustedForwarder; } function getTrustedForwarder() external view returns (address trustedForwarder) { return _trustedForwarder; } function _msgSender() internal view virtual returns (address sender) { if (isTrustedForwarder(msg.sender)) { require(msg.data.length >= 24, "ERC2771HandlerV2: Invalid msg.data"); // The assembly code is more direct than the Solidity version using `abi.decode`. // solhint-disable-next-line no-inline-assembly assembly { sender := shr(96, calldataload(sub(calldatasize(), 20))) } } else { return msg.sender; } } function _msgData() internal view virtual returns (bytes calldata) { if (isTrustedForwarder(msg.sender)) { require(msg.data.length >= 24, "ERC2771HandlerV2: Invalid msg.data"); return msg.data[:msg.data.length - 20]; } else { return msg.data; } } }
//SPDX-License-Identifier: MIT pragma solidity 0.8.2; import "@openzeppelin/contracts-0.8/utils/Context.sol"; import "@openzeppelin/contracts-0.8/token/ERC20/utils/SafeERC20.sol"; import {Address} from "@openzeppelin/contracts-0.8/utils/Address.sol"; abstract contract StakeTokenWrapper is Context { using Address for address; using SafeERC20 for IERC20; IERC20 internal _stakeToken; uint256 internal _totalSupply; mapping(address => uint256) internal _balances; constructor(IERC20 stakeToken) { require(address(stakeToken).isContract(), "StakeTokenWrapper: is not a contract"); _stakeToken = stakeToken; } function _stake(uint256 amount) internal virtual { require(amount > 0, "StakeTokenWrapper: amount > 0"); _totalSupply = _totalSupply + amount; _balances[_msgSender()] = _balances[_msgSender()] + amount; _stakeToken.safeTransferFrom(_msgSender(), address(this), amount); } function _withdraw(uint256 amount) internal virtual { require(amount > 0, "StakeTokenWrapper: amount > 0"); _totalSupply = _totalSupply - amount; _balances[_msgSender()] = _balances[_msgSender()] - amount; _stakeToken.safeTransfer(_msgSender(), amount); } uint256[50] private __gap; }
//SPDX-License-Identifier: MIT pragma solidity 0.8.2; interface IContributionRules { function computeMultiplier(address account, uint256 amountStaked) external returns (uint256); }
//SPDX-License-Identifier: MIT pragma solidity 0.8.2; /// @title Plugins for Reward Pools that calculate the rewards must implement this interface interface IRewardCalculator { /// @dev At any point in time this function must return the accumulated rewards from the last call to restartRewards function getRewards() external view returns (uint256); /// @dev The main contract has distributed the rewards (getRewards()) until this point, this must start /// @dev from scratch => getRewards() == 0 function restartRewards() external; }
//SPDX-License-Identifier: MIT pragma solidity 0.8.2; import {Context} from "@openzeppelin/contracts-0.8/utils/Context.sol"; import {Ownable} from "@openzeppelin/contracts-0.8/access/Ownable.sol"; // Note: this contract is meant to be inherited by ERC20RewardPool. // we should override the renounceOwnership() method otherwise. contract LockRules is Context, Ownable { // limits uint256 public constant timeLockLimit = 180 days; uint256 public constant amountLockLimit = 1000 ether; struct TimeLockClaim { uint256 lockPeriodInSecs; mapping(address => uint256) lastClaim; } struct AmountLockClaim { uint256 amount; bool claimLockEnabled; } struct TimeLockWithdraw { uint256 lockPeriodInSecs; mapping(address => uint256) lastWithdraw; } struct TimeLockDeposit { uint256 lockPeriodInSecs; mapping(address => uint256) lastDeposit; } event TimelockClaimSet(uint256 lockPeriodInSecs); event TimelockDepositSet(uint256 newTimeDeposit); event TimeLockWithdrawSet(uint256 newTimeWithdraw); event AmountLockClaimSet(uint256 newAmountLockClaim, bool isEnabled); // This is used to implement a time buffer for reward retrieval, so the user cannot re-stake the rewards too fast. TimeLockClaim public timeLockClaim; AmountLockClaim public amountLockClaim; TimeLockWithdraw public lockWithdraw; TimeLockDeposit public lockDeposit; modifier timeLockClaimCheck(address account) { // We use lockPeriodInSecs == 0 to disable this check if (timeLockClaim.lockPeriodInSecs != 0) { require( block.timestamp > timeLockClaim.lastClaim[account] + timeLockClaim.lockPeriodInSecs, "LockRules: Claim must wait" ); } timeLockClaim.lastClaim[account] = block.timestamp; _; } modifier antiWithdrawCheck(address account) { // We use lockPeriodInSecs == 0 to disable this check if (lockWithdraw.lockPeriodInSecs != 0) { require( block.timestamp > lockWithdraw.lastWithdraw[account] + lockWithdraw.lockPeriodInSecs, "LockRules: Withdraw must wait" ); } lockWithdraw.lastWithdraw[account] = block.timestamp; _; } modifier antiDepositCheck(address account) { // We use lockPeriodInSecs == 0 to disable this check if (lockDeposit.lockPeriodInSecs != 0) { require( block.timestamp > lockDeposit.lastDeposit[account] + lockDeposit.lockPeriodInSecs, "LockRules: Deposit must wait" ); } lockDeposit.lastDeposit[account] = block.timestamp; _; } /// @notice set the _lockPeriodInSecs for the anti-compound buffer /// @param _lockPeriodInSecs amount of time the user must wait between reward withdrawal function setTimelockClaim(uint256 _lockPeriodInSecs) external onlyOwner { require(_lockPeriodInSecs <= timeLockLimit, "LockRules: invalid lockPeriodInSecs"); timeLockClaim.lockPeriodInSecs = _lockPeriodInSecs; emit TimelockClaimSet(_lockPeriodInSecs); } function setTimelockDeposit(uint256 _newTimeDeposit) external onlyOwner { require(_newTimeDeposit <= timeLockLimit, "LockRules: invalid lockPeriodInSecs"); lockDeposit.lockPeriodInSecs = _newTimeDeposit; emit TimelockDepositSet(_newTimeDeposit); } function setTimeLockWithdraw(uint256 _newTimeWithdraw) external onlyOwner { require(_newTimeWithdraw <= timeLockLimit, "LockRules: invalid lockPeriodInSecs"); lockWithdraw.lockPeriodInSecs = _newTimeWithdraw; emit TimeLockWithdrawSet(_newTimeWithdraw); } function setAmountLockClaim(uint256 _newAmountLockClaim, bool _isEnabled) external onlyOwner { require(_newAmountLockClaim <= amountLockLimit, "LockRules: invalid newAmountLockClaim"); amountLockClaim.amount = _newAmountLockClaim; amountLockClaim.claimLockEnabled = _isEnabled; emit AmountLockClaimSet(_newAmountLockClaim, _isEnabled); } function getRemainingTimelockClaim() external view returns (uint256) { uint256 timeLock = (timeLockClaim.lastClaim[_msgSender()] + timeLockClaim.lockPeriodInSecs); if (timeLock > block.timestamp) { return timeLock - block.timestamp; } else { return 0; } } function getRemainingTimelockWithdraw() external view returns (uint256) { uint256 timeLock = (lockWithdraw.lastWithdraw[_msgSender()] + lockWithdraw.lockPeriodInSecs); if (timeLock > block.timestamp) { return timeLock - block.timestamp; } else { return 0; } } function getRemainingTimelockDeposit() external view returns (uint256) { uint256 timeLock = (lockDeposit.lastDeposit[_msgSender()] + lockDeposit.lockPeriodInSecs); if (timeLock > block.timestamp) { return timeLock - block.timestamp; } else { return 0; } } }
//SPDX-License-Identifier: MIT pragma solidity 0.8.2; import {Ownable} from "@openzeppelin/contracts-0.8/access/Ownable.sol"; import {Address} from "@openzeppelin/contracts-0.8/utils/Address.sol"; import {Math} from "@openzeppelin/contracts-0.8/utils/math/Math.sol"; import {IERC721} from "@openzeppelin/contracts-0.8/token/ERC721/IERC721.sol"; import {IERC1155} from "@openzeppelin/contracts-0.8/token/ERC1155/IERC1155.sol"; contract RequirementsRules is Ownable { using Address for address; // we limited the number of Ids and contracts that we can have in the lists // to avoid the risk of DoS caused by gas limits being exceeded during the iterations uint256 public idsLimit = 64; uint256 public contractsLimit = 4; // maxStake amount allowed if user has no ERC721 or ERC1155 uint256 public maxStakeOverall; struct ERC721RequirementRule { uint256[] ids; bool balanceOf; uint256 minAmountBalanceOf; uint256 maxAmountBalanceOf; uint256 minAmountId; uint256 maxAmountId; uint256 index; } struct ERC1155RequirementRule { uint256[] ids; uint256 minAmountId; uint256 maxAmountId; uint256 index; } mapping(IERC721 => ERC721RequirementRule) internal _listERC721; mapping(IERC1155 => ERC1155RequirementRule) internal _listERC1155; IERC721[] internal _listERC721Index; IERC1155[] internal _listERC1155Index; event ERC1155RequirementListSet( address indexed contractERC1155, uint256[] ids, uint256 minAmountId, uint256 maxAmountId ); event ERC721RequirementListSet( address indexed contractERC721, uint256[] ids, bool balanceOf, uint256 minAmountBalanceOf, uint256 maxAmountBalanceOf, uint256 minAmountId, uint256 maxAmountId ); event MaxStakeOverallSet(uint256 newMaxStake, uint256 oldMaxStake); event ERC11551RequirementListDeleted(address indexed contractERC1155); event ERC721RequirementListDeleted(address indexed contractERC721); modifier isContract(address account) { require(account.isContract(), "RequirementsRules: is not contract"); _; } modifier checkRequirements( address account, uint256 amount, uint256 balanceOf ) { uint256 maxStakeERC721 = checkAndGetERC721Stake(account); uint256 maxStakeERC1155 = checkAndGetERC1155Stake(account); uint256 maxAllowed = _maxStakeAllowedCalculator(maxStakeERC721, maxStakeERC1155); if ((maxAllowed > 0) || _listERC721Index.length > 0 || _listERC1155Index.length > 0) { require(amount + balanceOf <= maxAllowed, "RequirementsRules: maxAllowed"); } _; } modifier isERC721MemberList(address contractERC721) { require( isERC721MemberRequirementList(IERC721(contractERC721)), "RequirementsRules: contract is not in the list" ); _; } modifier isERC1155MemberList(address contractERC1155) { require( isERC1155MemberRequirementList(IERC1155(contractERC1155)), "RequirementsRules: contract is not in the list" ); _; } // if user has not erc721 or erc1155 function setMaxStakeOverall(uint256 newMaxStake) external onlyOwner { uint256 oldMaxStake = maxStakeOverall; maxStakeOverall = newMaxStake; emit MaxStakeOverallSet(newMaxStake, oldMaxStake); } function setERC721RequirementList( address contractERC721, uint256[] memory ids, bool balanceOf, uint256 minAmountBalanceOf, uint256 maxAmountBalanceOf, uint256 minAmountId, uint256 maxAmountId ) external onlyOwner isContract(contractERC721) { require( (balanceOf == true && ids.length == 0 && minAmountBalanceOf > 0 && maxAmountBalanceOf > 0) || (balanceOf == false && ids.length > 0 && minAmountId > 0 && maxAmountId > 0 && ids.length <= idsLimit), "RequirementRules: invalid list" ); IERC721 newContract = IERC721(contractERC721); if (ids.length != 0) { _listERC721[newContract].ids = ids; } _listERC721[newContract].minAmountBalanceOf = minAmountBalanceOf; _listERC721[newContract].maxAmountBalanceOf = maxAmountBalanceOf; _listERC721[newContract].minAmountId = minAmountId; _listERC721[newContract].maxAmountId = maxAmountId; _listERC721[newContract].balanceOf = balanceOf; // if it's a new member create a new registry, instead, only update if (isERC721MemberRequirementList(newContract) == false) { // Limiting the size of the array (interations) to avoid the risk of DoS. require(contractsLimit > _listERC721Index.length, "RequirementsRules: contractsLimit exceeded"); _listERC721Index.push(newContract); _listERC721[newContract].index = _listERC721Index.length - 1; } emit ERC721RequirementListSet( contractERC721, ids, balanceOf, minAmountBalanceOf, maxAmountBalanceOf, minAmountId, maxAmountId ); } function setERC1155RequirementList( address contractERC1155, uint256[] memory ids, uint256 minAmountId, uint256 maxAmountId ) external onlyOwner isContract(contractERC1155) { require( ids.length > 0 && minAmountId > 0 && maxAmountId > 0 && ids.length <= idsLimit, "RequirementRules: invalid list" ); IERC1155 newContract = IERC1155(contractERC1155); _listERC1155[newContract].ids = ids; _listERC1155[newContract].minAmountId = minAmountId; _listERC1155[newContract].maxAmountId = maxAmountId; // if it's a new member create a new registry, instead, only update if (isERC1155MemberRequirementList(newContract) == false) { // Limiting the size of the array (interations) to avoid the risk of DoS. require(contractsLimit > _listERC1155Index.length, "RequirementsRules: contractsLimit exceeded"); _listERC1155Index.push(newContract); _listERC1155[newContract].index = _listERC1155Index.length - 1; } emit ERC1155RequirementListSet(contractERC1155, ids, minAmountId, maxAmountId); } function getERC721RequirementList(address contractERC721) external view isContract(contractERC721) isERC721MemberList(contractERC721) returns (ERC721RequirementRule memory) { return _listERC721[IERC721(contractERC721)]; } function getERC1155RequirementList(address contractERC1155) external view isContract(contractERC1155) isERC1155MemberList(contractERC1155) returns (ERC1155RequirementRule memory) { return _listERC1155[IERC1155(contractERC1155)]; } function deleteERC721RequirementList(address contractERC721) external onlyOwner isContract(contractERC721) isERC721MemberList(contractERC721) { IERC721 reqContract = IERC721(contractERC721); uint256 indexToDelete = _listERC721[reqContract].index; IERC721 addrToMove = _listERC721Index[_listERC721Index.length - 1]; _listERC721Index[indexToDelete] = addrToMove; _listERC721[addrToMove].index = indexToDelete; _listERC721Index.pop(); emit ERC721RequirementListDeleted(contractERC721); } function deleteERC1155RequirementList(address contractERC1155) external onlyOwner isContract(contractERC1155) isERC1155MemberList(contractERC1155) { IERC1155 reqContract = IERC1155(contractERC1155); uint256 indexToDelete = _listERC1155[reqContract].index; IERC1155 addrToMove = _listERC1155Index[_listERC1155Index.length - 1]; _listERC1155Index[indexToDelete] = addrToMove; _listERC1155[addrToMove].index = indexToDelete; _listERC1155Index.pop(); emit ERC11551RequirementListDeleted(contractERC1155); } function isERC721MemberRequirementList(IERC721 reqContract) public view returns (bool) { return (_listERC721Index.length != 0) && (_listERC721Index[_listERC721[reqContract].index] == reqContract); } function isERC1155MemberRequirementList(IERC1155 reqContract) public view returns (bool) { return (_listERC1155Index.length != 0) && (_listERC1155Index[_listERC1155[reqContract].index] == reqContract); } function getERC721MaxStake(address account) public view returns (uint256) { uint256 _maxStake = 0; for (uint256 i = 0; i < _listERC721Index.length; i++) { uint256 balanceOf = 0; uint256 balanceOfId = 0; IERC721 reqContract = _listERC721Index[i]; if (_listERC721[reqContract].balanceOf == true) { balanceOf = reqContract.balanceOf(account); } else { balanceOfId = getERC721BalanceId(reqContract, account); } _maxStake = _maxStake + (balanceOf * _listERC721[reqContract].maxAmountBalanceOf + balanceOfId * _listERC721[reqContract].maxAmountId); } return _maxStake; } function getERC1155MaxStake(address account) public view returns (uint256) { uint256 _maxStake = 0; for (uint256 i = 0; i < _listERC1155Index.length; i++) { uint256 _totalBal = 0; IERC1155 reqContract = _listERC1155Index[i]; uint256 bal = getERC1155BalanceId(reqContract, account); _totalBal = _totalBal + bal; _maxStake = _maxStake + (_totalBal * _listERC1155[reqContract].maxAmountId); } return _maxStake; } function maxStakeAllowedCalculator(address account) public view returns (uint256) { uint256 maxStakeERC721 = getERC721MaxStake(account); uint256 maxStakeERC1155 = getERC1155MaxStake(account); return _maxStakeAllowedCalculator(maxStakeERC721, maxStakeERC1155); } function getERC721BalanceId(IERC721 reqContract, address account) public view returns (uint256) { uint256 balanceOfId = 0; for (uint256 j = 0; j < _listERC721[reqContract].ids.length; j++) { address owner = reqContract.ownerOf(_listERC721[reqContract].ids[j]); if (owner == account) { ++balanceOfId; } } return balanceOfId; } function getERC1155BalanceId(IERC1155 reqContract, address account) public view returns (uint256) { uint256 balanceOfId = 0; for (uint256 j = 0; j < _listERC1155[reqContract].ids.length; j++) { uint256 bal = reqContract.balanceOf(account, _listERC1155[reqContract].ids[j]); balanceOfId = balanceOfId + bal; } return balanceOfId; } function checkAndGetERC1155Stake(address account) public view returns (uint256) { uint256 _maxStake = 0; for (uint256 i = 0; i < _listERC1155Index.length; i++) { uint256 _totalBal = 0; IERC1155 reqContract = _listERC1155Index[i]; uint256 balanceId = getERC1155BalanceId(reqContract, account); if (_listERC1155[reqContract].ids.length > 0) { require(balanceId >= _listERC1155[reqContract].minAmountId, "RequirementsRules: balanceId"); } _totalBal = _totalBal + balanceId; _maxStake = _maxStake + (_totalBal * _listERC1155[reqContract].maxAmountId); } return _maxStake; } function checkAndGetERC721Stake(address account) public view returns (uint256) { uint256 _maxStake = 0; for (uint256 i = 0; i < _listERC721Index.length; i++) { uint256 balanceOf = 0; uint256 balanceOfId = 0; IERC721 reqContract = _listERC721Index[i]; if (_listERC721[reqContract].balanceOf == true) { require( (reqContract.balanceOf(account) >= _listERC721[reqContract].minAmountBalanceOf) || (maxStakeOverall > 0), "RequirementsRules: balanceOf" ); balanceOf = reqContract.balanceOf(account); } else { balanceOfId = getERC721BalanceId(reqContract, account); if (_listERC721[reqContract].ids.length > 0) { require( (balanceOfId >= _listERC721[reqContract].minAmountId) || (maxStakeOverall > 0), "RequirementsRules: balanceId" ); } } _maxStake = _maxStake + (balanceOf * _listERC721[reqContract].maxAmountBalanceOf + balanceOfId * _listERC721[reqContract].maxAmountId); } return _maxStake; } function _maxStakeAllowedCalculator(uint256 maxStakeERC721, uint256 maxStakeERC1155) internal view returns (uint256) { uint256 maxAllowed = maxStakeOverall; if (maxStakeERC721 + maxStakeERC1155 > 0) { if (maxStakeOverall > 0) { maxAllowed = Math.min(maxAllowed, maxStakeERC721 + maxStakeERC1155); } else { maxAllowed = maxStakeERC721 + maxStakeERC1155; } } else { maxAllowed = maxStakeOverall; } return maxAllowed; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool _approved) external; /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes calldata data ) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC1155/IERC1155.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC1155 compliant contract, as defined in the * https://eips.ethereum.org/EIPS/eip-1155[EIP]. * * _Available since v3.1._ */ interface IERC1155 is IERC165 { /** * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`. */ event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value); /** * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all * transfers. */ event TransferBatch( address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values ); /** * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to * `approved`. */ event ApprovalForAll(address indexed account, address indexed operator, bool approved); /** * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI. * * If an {URI} event was emitted for `id`, the standard * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value * returned by {IERC1155MetadataURI-uri}. */ event URI(string value, uint256 indexed id); /** * @dev Returns the amount of tokens of token type `id` owned by `account`. * * Requirements: * * - `account` cannot be the zero address. */ function balanceOf(address account, uint256 id) external view returns (uint256); /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}. * * Requirements: * * - `accounts` and `ids` must have the same length. */ function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids) external view returns (uint256[] memory); /** * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`, * * Emits an {ApprovalForAll} event. * * Requirements: * * - `operator` cannot be the caller. */ function setApprovalForAll(address operator, bool approved) external; /** * @dev Returns true if `operator` is approved to transfer ``account``'s tokens. * * See {setApprovalForAll}. */ function isApprovedForAll(address account, address operator) external view returns (bool); /** * @dev Transfers `amount` tokens of token type `id` from `from` to `to`. * * Emits a {TransferSingle} event. * * Requirements: * * - `to` cannot be the zero address. * - If the caller is not `from`, it must be have been approved to spend ``from``'s tokens via {setApprovalForAll}. * - `from` must have a balance of tokens of type `id` of at least `amount`. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the * acceptance magic value. */ function safeTransferFrom( address from, address to, uint256 id, uint256 amount, bytes calldata data ) external; /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}. * * Emits a {TransferBatch} event. * * Requirements: * * - `ids` and `amounts` must have the same length. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the * acceptance magic value. */ function safeBatchTransferFrom( address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data ) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
{ "optimizer": { "enabled": true, "runs": 2000 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"contract IERC20","name":"stakeToken_","type":"address"},{"internalType":"contract IERC20","name":"rewardToken_","type":"address"},{"internalType":"address","name":"trustedForwarder","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newAmountLockClaim","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isEnabled","type":"bool"}],"name":"AmountLockClaimSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"newContribution","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldContribution","type":"uint256"}],"name":"ContributionUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"contractERC1155","type":"address"}],"name":"ERC11551RequirementListDeleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"contractERC1155","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"minAmountId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"maxAmountId","type":"uint256"}],"name":"ERC1155RequirementListSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"contractERC721","type":"address"}],"name":"ERC721RequirementListDeleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"contractERC721","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"indexed":false,"internalType":"bool","name":"balanceOf","type":"bool"},{"indexed":false,"internalType":"uint256","name":"minAmountBalanceOf","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"maxAmountBalanceOf","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"minAmountId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"maxAmountId","type":"uint256"}],"name":"ERC721RequirementListSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"Exit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newMaxStake","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldMaxStake","type":"uint256"}],"name":"MaxStakeOverallSet","type":"event"},{"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":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"rewardAmount","type":"uint256"}],"name":"RewardPaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"stakeAmount","type":"uint256"}],"name":"Staked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newTimeWithdraw","type":"uint256"}],"name":"TimeLockWithdrawSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"lockPeriodInSecs","type":"uint256"}],"name":"TimelockClaimSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newTimeDeposit","type":"uint256"}],"name":"TimelockDepositSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"stakeAmount","type":"uint256"}],"name":"Withdrawn","type":"event"},{"inputs":[],"name":"amountLockClaim","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"claimLockEnabled","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"amountLockLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"checkAndGetERC1155Stake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"checkAndGetERC721Stake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"computeContribution","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"}],"name":"computeContributionInBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"contractsLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"contributionOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"contributionRules","outputs":[{"internalType":"contract IContributionRules","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"contractERC1155","type":"address"}],"name":"deleteERC1155RequirementList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contractERC721","type":"address"}],"name":"deleteERC721RequirementList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"earned","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"exit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC1155","name":"reqContract","type":"address"},{"internalType":"address","name":"account","type":"address"}],"name":"getERC1155BalanceId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getERC1155MaxStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"contractERC1155","type":"address"}],"name":"getERC1155RequirementList","outputs":[{"components":[{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256","name":"minAmountId","type":"uint256"},{"internalType":"uint256","name":"maxAmountId","type":"uint256"},{"internalType":"uint256","name":"index","type":"uint256"}],"internalType":"struct RequirementsRules.ERC1155RequirementRule","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC721","name":"reqContract","type":"address"},{"internalType":"address","name":"account","type":"address"}],"name":"getERC721BalanceId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getERC721MaxStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"contractERC721","type":"address"}],"name":"getERC721RequirementList","outputs":[{"components":[{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"bool","name":"balanceOf","type":"bool"},{"internalType":"uint256","name":"minAmountBalanceOf","type":"uint256"},{"internalType":"uint256","name":"maxAmountBalanceOf","type":"uint256"},{"internalType":"uint256","name":"minAmountId","type":"uint256"},{"internalType":"uint256","name":"maxAmountId","type":"uint256"},{"internalType":"uint256","name":"index","type":"uint256"}],"internalType":"struct RequirementsRules.ERC721RequirementRule","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRemainingTimelockClaim","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRemainingTimelockDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRemainingTimelockWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getRewardsAvailable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTrustedForwarder","outputs":[{"internalType":"address","name":"trustedForwarder","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"idsLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC1155","name":"reqContract","type":"address"}],"name":"isERC1155MemberRequirementList","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC721","name":"reqContract","type":"address"}],"name":"isERC721MemberRequirementList","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"forwarder","type":"address"}],"name":"isTrustedForwarder","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lockDeposit","outputs":[{"internalType":"uint256","name":"lockPeriodInSecs","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lockWithdraw","outputs":[{"internalType":"uint256","name":"lockPeriodInSecs","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"maxStakeAllowedCalculator","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxStakeOverall","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"recoverFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[],"name":"restartRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardCalculator","outputs":[{"internalType":"contract IRewardCalculator","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardPerToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardPerTokenStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newAmountLockClaim","type":"uint256"},{"internalType":"bool","name":"_isEnabled","type":"bool"}],"name":"setAmountLockClaim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"}],"name":"setContributionRules","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contractERC1155","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256","name":"minAmountId","type":"uint256"},{"internalType":"uint256","name":"maxAmountId","type":"uint256"}],"name":"setERC1155RequirementList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contractERC721","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"bool","name":"balanceOf","type":"bool"},{"internalType":"uint256","name":"minAmountBalanceOf","type":"uint256"},{"internalType":"uint256","name":"maxAmountBalanceOf","type":"uint256"},{"internalType":"uint256","name":"minAmountId","type":"uint256"},{"internalType":"uint256","name":"maxAmountId","type":"uint256"}],"name":"setERC721RequirementList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newMaxStake","type":"uint256"}],"name":"setMaxStakeOverall","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"bool","name":"restartRewards_","type":"bool"}],"name":"setRewardCalculator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"}],"name":"setRewardToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"}],"name":"setStakeToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newTimeWithdraw","type":"uint256"}],"name":"setTimeLockWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lockPeriodInSecs","type":"uint256"}],"name":"setTimelockClaim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newTimeDeposit","type":"uint256"}],"name":"setTimelockDeposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"trustedForwarder","type":"address"}],"name":"setTrustedForwarder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stakeToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"timeLockClaim","outputs":[{"internalType":"uint256","name":"lockPeriodInSecs","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"timeLockLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalContributions","outputs":[{"internalType":"uint256","name":"","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":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"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"}]
Contract Creation Code
60806040526040603e556004603f553480156200001b57600080fd5b50604051620058d8380380620058d88339810160408190526200003e91620002b9565b82620000536200004d620001b9565b620001d6565b62000072816001600160a01b03166200022660201b6200407c1760201c565b620000d05760405162461bcd60e51b8152602060048201526024808201527f5374616b65546f6b656e577261707065723a206973206e6f74206120636f6e746044820152631c9858dd60e21b60648201526084015b60405180910390fd5b600180546001600160a01b0319166001600160a01b039283161781556045556046805460ff60a01b191690556200011590831662000226602090811b6200407c17901c565b6200016e5760405162461bcd60e51b815260206004820152602260248201527f4552433230526577617264506f6f6c3a206973206e6f74206120636f6e74726160448201526118dd60f21b6064820152608401620000c7565b604880546001600160a01b0319166001600160a01b038416179055620001b081604680546001600160a01b0319166001600160a01b0392909216919091179055565b50505062000325565b6000620001d06200022c60201b620040821760201c565b90505b90565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b3b151590565b6046546000906001600160a01b0316331415620002b1576018361015620002a15760405162461bcd60e51b815260206004820152602260248201527f4552433237373148616e646c657256323a20496e76616c6964206d73672e6461604482015261746160f01b6064820152608401620000c7565b5060131936013560601c620001d3565b5033620001d3565b600080600060608486031215620002ce578283fd5b8351620002db816200030c565b6020850151909350620002ee816200030c565b604085015190925062000301816200030c565b809150509250925092565b6001600160a01b03811681146200032257600080fd5b50565b6155a380620003356000396000f3fe608060405234801561001057600080fd5b50600436106104205760003560e01c80638456cb5911610235578063cd3daf9d11610135578063df136d65116100c8578063e9fad8ee11610097578063f2fde38b1161007c578063f2fde38b146108b3578063f7c618c1146108c6578063fc17e07b146108d957610420565b8063e9fad8ee146108a2578063f0f49856146108aa57610420565b8063df136d651461086a578063dfeb943914610873578063e255911214610886578063e72f6e301461088f57610420565b8063d64791f811610104578063d64791f814610808578063d7805ece1461081b578063da74222814610844578063db6beab71461085757610420565b8063cd3daf9d146107d2578063ce1b815f146107da578063d1b844e6146107eb578063d2fe29d3146107f557610420565b8063a3c5b4d6116101c8578063a8863bb111610197578063b01658401161017c578063b0165840146107a4578063bd8e10f4146107ac578063bfcd5953146107bf57610420565b8063a8863bb11461077e578063accb04bd1461079157610420565b8063a3c5b4d61461073b578063a425632f1461074e578063a5cac0a114610758578063a694fc3a1461076b57610420565b80638da5cb5b116102045780638da5cb5b146106fa57806396769e891461070b5780639c48f2901461071e578063a0ed0d8e1461072857610420565b80638456cb59146106b757806387f260ce146106bf5780638aee8127146106c75780638b876347146106da57610420565b80633f4ba83a116103405780635c9415d3116102d35780636e15349b116102a257806370a082311161028757806370a0823114610666578063715018a61461068f5780637f7bc9061461069757610420565b80636e15349b1461064b5780636e6982af1461065e57610420565b80635c9415d3146106095780635c975abb1461061c578063618891101461062f57806369354e5c1461064257610420565b80634d49d3991161030f5780634d49d399146105c457806351ed6a30146105ce578063572b6c05146105df5780635ae64bd81461060157610420565b80633f4ba83a14610583578063431e48af1461058b578063446ed03d1461059e578063495bb729146105b157610420565b8063216213d5116103b85780632e0cefd7116103875780632e0cefd71461053d5780632e1a7d4d1461056057806337c08923146105735780633d18b9121461057b57610420565b8063216213d5146104c65780632b061ca2146104d95780632b7f01fc146104ff5780632c34a4591461052a57610420565b80630d59f435116103f45780630d59f435146104935780631657e4891461049b57806318160ddd146104ae5780631860f70d146104b657610420565b80628cc262146104255780630397d4581461044b5780630700037d146104605780630823a11614610480575b600080fd5b610438610433366004615055565b6108f9565b6040519081526020015b60405180910390f35b61045e610459366004615055565b610937565b005b61043861046e366004615055565b604c6020526000908152604090205481565b61043861048e366004615055565b610bfc565b610438610ef5565b6104386104a9366004615055565b610f5e565b600254610438565b610438683635c9adc5dea0000081565b61045e6104d4366004615055565b610f8b565b6038546039546104ea919060ff1682565b60408051928352901515602083015201610442565b604954610512906001600160a01b031681565b6040516001600160a01b039091168152602001610442565b610438610538366004615055565b611227565b61055061054b366004615055565b6112d1565b6040519015158152602001610442565b61045e61056e366004615260565b61133b565b604d54610438565b61045e61141f565b61045e6114f7565b61045e610599366004615290565b61157a565b6104386105ac366004615055565b6116c7565b61045e6105bf366004615055565b6117fb565b61043862ed4e0081565b6001546001600160a01b0316610512565b6105506105ed366004615055565b6046546001600160a01b0390811691161490565b610438611a97565b61045e610617366004615260565b611bc1565b610550604654600160a01b900460ff1690565b61045e61063d366004615260565b611cd5565b61043860405481565b610438610659366004615233565b611de2565b610438611f13565b610438610674366004615055565b6001600160a01b031660009081526003602052604090205490565b61045e611f26565b6106aa6106a5366004615055565b61200d565b60405161044291906153e4565b61045e6121ec565b61043861226d565b61045e6106d5366004615055565b612280565b6104386106e8366004615055565b604b6020526000908152604090205481565b6000546001600160a01b0316610512565b604a54610512906001600160a01b031681565b6036546104389081565b61045e610736366004615112565b612540565b61045e61074936600461508d565b612830565b603a546104389081565b610550610766366004615055565b612b86565b61045e610779366004615260565b612bd4565b61043861078c366004615233565b6130f5565b61045e61079f366004615170565b613210565b61045e613377565b61045e6107ba366004615055565b61337f565b61045e6107cd366004615260565b6134d6565b61043861358c565b6046546001600160a01b0316610512565b603c546104389081565b61045e610803366004615260565b6135a3565b61045e6108163660046151a8565b6136b0565b610438610829366004615055565b6001600160a01b03166000908152604e602052604090205490565b61045e610852366004615055565b61373b565b610438610865366004615055565b61383a565b61043860475481565b61045e610881366004615055565b6139ae565b610438603e5481565b61045e61089d366004615055565b613a1b565b61045e613c8a565b610438603f5481565b61045e6108c1366004615055565b613dd7565b604854610512906001600160a01b031681565b6108ec6108e7366004615055565b613ed8565b604051610442919061539e565b600061090c82610907614143565b614212565b6001600160a01b0383166000908152604c602052604090205461092f919061544b565b90505b919050565b806001600160a01b0381163b61099f5760405162461bcd60e51b815260206004820152602260248201527f4552433230526577617264506f6f6c3a206973206e6f74206120636f6e74726160448201526118dd60f21b60648201526084015b60405180910390fd5b6109a7614276565b6001600160a01b03166109c26000546001600160a01b031690565b6001600160a01b031614610a185760405162461bcd60e51b815260206004820152601a60248201527f4552433230526577617264506f6f6c3a206e6f742061646d696e0000000000006044820152606401610996565b816001600160a01b038116610a6f5760405162461bcd60e51b815260206004820152601d60248201527f4552433230526577617264506f6f6c3a207a65726f20616464726573730000006044820152606401610996565b6040516370a0823160e01b815230600482015283906001600160a01b038216906370a082319060240160206040518083038186803b158015610ab057600080fd5b505afa158015610ac4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ae89190615278565b6001546040516370a0823160e01b81523060048201526001600160a01b03909116906370a082319060240160206040518083038186803b158015610b2b57600080fd5b505afa158015610b3f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b639190615278565b1115610bd75760405162461bcd60e51b815260206004820152602560248201527f4552433230526577617264506f6f6c3a20696e73756666696369656e7420626160448201527f6c616e63650000000000000000000000000000000000000000000000000000006064820152608401610996565b600180546001600160a01b0319166001600160a01b0392909216919091179055505050565b600080805b604354811015610eee57600080600060438481548110610c3157634e487b7160e01b600052603260045260246000fd5b60009182526020808320909101546001600160a01b03168083526041909152604090912060019081015491925060ff90911615151415610dd3576001600160a01b03818116600081815260416020526040908190206002015490516370a0823160e01b8152928a166004840152916370a082319060240160206040518083038186803b158015610cc057600080fd5b505afa158015610cd4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cf89190615278565b101580610d0757506000604054115b610d535760405162461bcd60e51b815260206004820152601c60248201527f526571756972656d656e747352756c65733a2062616c616e63654f66000000006044820152606401610996565b6040516370a0823160e01b81526001600160a01b0388811660048301528216906370a082319060240160206040518083038186803b158015610d9457600080fd5b505afa158015610da8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dcc9190615278565b9250610e76565b610ddd81886130f5565b6001600160a01b03821660009081526041602052604090205490925015610e76576001600160a01b03811660009081526041602052604090206004015482101580610e2a57506000604054115b610e765760405162461bcd60e51b815260206004820152601c60248201527f526571756972656d656e747352756c65733a2062616c616e63654964000000006044820152606401610996565b6001600160a01b038116600090815260416020526040902060050154610e9c9083615477565b6001600160a01b038216600090815260416020526040902060030154610ec29085615477565b610ecc919061544b565b610ed6908661544b565b94505050508080610ee6906154d9565b915050610c01565b5092915050565b603c546000908190603d82610f08614276565b6001600160a01b03166001600160a01b0316815260200190815260200160002054610f33919061544b565b905042811115610f4f57610f474282615496565b915050610f5b565b6000915050610f5b565b505b90565b600080610f6a8361383a565b90506000610f7784611227565b9050610f838282614280565b949350505050565b610f93614276565b6001600160a01b0316610fae6000546001600160a01b031690565b6001600160a01b0316146110045760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610996565b806001600160a01b0381163b6110675760405162461bcd60e51b815260206004820152602260248201527f526571756972656d656e747352756c65733a206973206e6f7420636f6e74726160448201526118dd60f21b6064820152608401610996565b81611071816112d1565b6110e35760405162461bcd60e51b815260206004820152602e60248201527f526571756972656d656e747352756c65733a20636f6e7472616374206973206e60448201527f6f7420696e20746865206c6973740000000000000000000000000000000000006064820152608401610996565b6001600160a01b038316600090815260416020526040812060060154604380548693919061111390600190615496565b8154811061113157634e487b7160e01b600052603260045260246000fd5b600091825260209091200154604380546001600160a01b03909216925082918490811061116e57634e487b7160e01b600052603260045260246000fd5b600091825260208083209190910180546001600160a01b0319166001600160a01b03948516179055918316815260419091526040902060060182905560438054806111c957634e487b7160e01b600052603160045260246000fd5b600082815260208120820160001990810180546001600160a01b03191690559091019091556040516001600160a01b038816917f47e3c945866c02102662275722b0b8ae9769ad96d6ddcc8a4c6d8d74ff16706291a2505050505050565b600080805b604454811015610eee576000806044838154811061125a57634e487b7160e01b600052603260045260246000fd5b60009182526020822001546001600160a01b0316915061127a8288611de2565b9050611286818461544b565b6001600160a01b0383166000908152604260205260409020600201549093506112af9084615477565b6112b9908661544b565b945050505080806112c9906154d9565b91505061122c565b6043546000901580159061092f57506001600160a01b03821660008181526041602052604090206006015460438054909190811061131f57634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546001600160a01b03161492915050565b6002604554141561138e5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610996565b60026045556113a6604654600160a01b900460ff1690565b156113e65760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610996565b6113f66113f1614276565b6142d6565b611407611401614276565b826142e7565b611417611412614276565b614471565b506001604555565b600260455414156114725760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610996565b600260455561148a604654600160a01b900460ff1690565b156114ca5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610996565b6114d56113f1614276565b6114e56114e0614276565b61450b565b6114f0611412614276565b6001604555565b6114ff614276565b6001600160a01b031661151a6000546001600160a01b031690565b6001600160a01b0316146115705760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610996565b6115786146dc565b565b611582614276565b6001600160a01b031661159d6000546001600160a01b031690565b6001600160a01b0316146115f35760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610996565b683635c9adc5dea000008211156116725760405162461bcd60e51b815260206004820152602560248201527f4c6f636b52756c65733a20696e76616c6964206e6577416d6f756e744c6f636b60448201527f436c61696d0000000000000000000000000000000000000000000000000000006064820152608401610996565b60388290556039805460ff19168215159081179091556040805184815260208101929092527fae4d8a2a6d24c92b12bc1ad576eb89a6c352b143519ecbc978c0f5d75bb1d9c791015b60405180910390a15050565b600080805b604454811015610eee57600080604483815481106116fa57634e487b7160e01b600052603260045260246000fd5b60009182526020822001546001600160a01b0316915061171a8288611de2565b6001600160a01b038316600090815260426020526040902054909150156117a6576001600160a01b0382166000908152604260205260409020600101548110156117a65760405162461bcd60e51b815260206004820152601c60248201527f526571756972656d656e747352756c65733a2062616c616e63654964000000006044820152606401610996565b6117b0818461544b565b6001600160a01b0383166000908152604260205260409020600201549093506117d99084615477565b6117e3908661544b565b945050505080806117f3906154d9565b9150506116cc565b611803614276565b6001600160a01b031661181e6000546001600160a01b031690565b6001600160a01b0316146118745760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610996565b806001600160a01b0381163b6118d75760405162461bcd60e51b815260206004820152602260248201527f526571756972656d656e747352756c65733a206973206e6f7420636f6e74726160448201526118dd60f21b6064820152608401610996565b816118e181612b86565b6119535760405162461bcd60e51b815260206004820152602e60248201527f526571756972656d656e747352756c65733a20636f6e7472616374206973206e60448201527f6f7420696e20746865206c6973740000000000000000000000000000000000006064820152608401610996565b6001600160a01b038316600090815260426020526040812060030154604480548693919061198390600190615496565b815481106119a157634e487b7160e01b600052603260045260246000fd5b600091825260209091200154604480546001600160a01b0390921692508291849081106119de57634e487b7160e01b600052603260045260246000fd5b600091825260208083209190910180546001600160a01b0319166001600160a01b0394851617905591831681526042909152604090206003018290556044805480611a3957634e487b7160e01b600052603160045260246000fd5b600082815260208120820160001990810180546001600160a01b03191690559091019091556040516001600160a01b038816917f08617ff2b2e08e21be93ba4e04edc58f73671d33133725194bb67fddd33b1eb091a2505050505050565b6001546048546000916001600160a01b03918216911614611b34576048546040516370a0823160e01b81523060048201526001600160a01b03909116906370a082319060240160206040518083038186803b158015611af557600080fd5b505afa158015611b09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b2d9190615278565b9050610f5b565b6002546001546040516370a0823160e01b81523060048201526001600160a01b03909116906370a082319060240160206040518083038186803b158015611b7a57600080fd5b505afa158015611b8e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bb29190615278565b611bbc9190615496565b905090565b611bc9614276565b6001600160a01b0316611be46000546001600160a01b031690565b6001600160a01b031614611c3a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610996565b62ed4e00811115611c995760405162461bcd60e51b815260206004820152602360248201527f4c6f636b52756c65733a20696e76616c6964206c6f636b506572696f64496e5360448201526265637360e81b6064820152608401610996565b603a8190556040518181527f0a34a7f0967a1c454102f82743b9dcf955188e0a030905740e2c8a5b39910660906020015b60405180910390a150565b611cdd614276565b6001600160a01b0316611cf86000546001600160a01b031690565b6001600160a01b031614611d4e5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610996565b62ed4e00811115611dad5760405162461bcd60e51b815260206004820152602360248201527f4c6f636b52756c65733a20696e76616c6964206c6f636b506572696f64496e5360448201526265637360e81b6064820152608401610996565b60368190556040518181527f1bc5ec4d2816c06ea16ad9f0e99eb3c74517b041ed9d0a7103dd6f775cd66f7c90602001611cca565b600080805b6001600160a01b038516600090815260426020526040902054811015611f0b576001600160a01b0385166000818152604260205260408120805491929162fdd58e91889186908110611e4957634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b039092166004830152602482015260440160206040518083038186803b158015611eb157600080fd5b505afa158015611ec5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ee99190615278565b9050611ef5818461544b565b9250508080611f03906154d9565b915050611de7565b509392505050565b6036546000908190603782610f08614276565b611f2e614276565b6001600160a01b0316611f496000546001600160a01b031690565b6001600160a01b031614611f9f5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610996565b60405162461bcd60e51b815260206004820152602860248201527f4552433230526577617264506f6f6c3a2063616e27742072656e6f756e63654f60448201527f776e6572736869700000000000000000000000000000000000000000000000006064820152608401610996565b61204f6040518060e001604052806060815260200160001515815260200160008152602001600081526020016000815260200160008152602001600081525090565b816001600160a01b0381163b6120b25760405162461bcd60e51b815260206004820152602260248201527f526571756972656d656e747352756c65733a206973206e6f7420636f6e74726160448201526118dd60f21b6064820152608401610996565b826120bc816112d1565b61212e5760405162461bcd60e51b815260206004820152602e60248201527f526571756972656d656e747352756c65733a20636f6e7472616374206973206e60448201527f6f7420696e20746865206c6973740000000000000000000000000000000000006064820152608401610996565b6001600160a01b038416600090815260416020908152604091829020825181546101009381028201840190945260e08101848152909391928492849184018282801561219957602002820191906000526020600020905b815481526020019060010190808311612185575b5050509183525050600182015460ff1615156020820152600282015460408201526003820154606082015260048201546080820152600582015460a082015260069091015460c090910152949350505050565b6121f4614276565b6001600160a01b031661220f6000546001600160a01b031690565b6001600160a01b0316146122655760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610996565b6115786147a9565b603a546000908190603b82610f08614276565b806001600160a01b0381163b6122e35760405162461bcd60e51b815260206004820152602260248201527f4552433230526577617264506f6f6c3a206973206e6f74206120636f6e74726160448201526118dd60f21b6064820152608401610996565b6122eb614276565b6001600160a01b03166123066000546001600160a01b031690565b6001600160a01b03161461235c5760405162461bcd60e51b815260206004820152601a60248201527f4552433230526577617264506f6f6c3a206e6f742061646d696e0000000000006044820152606401610996565b816001600160a01b0381166123b35760405162461bcd60e51b815260206004820152601d60248201527f4552433230526577617264506f6f6c3a207a65726f20616464726573730000006044820152606401610996565b6040516370a0823160e01b815230600482015283906001600160a01b038216906370a082319060240160206040518083038186803b1580156123f457600080fd5b505afa158015612408573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061242c9190615278565b6048546040516370a0823160e01b81523060048201526001600160a01b03909116906370a082319060240160206040518083038186803b15801561246f57600080fd5b505afa158015612483573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124a79190615278565b111561251b5760405162461bcd60e51b815260206004820152602560248201527f4552433230526577617264506f6f6c3a20696e73756666696369656e7420626160448201527f6c616e63650000000000000000000000000000000000000000000000000000006064820152608401610996565b604880546001600160a01b0319166001600160a01b0392909216919091179055505050565b612548614276565b6001600160a01b03166125636000546001600160a01b031690565b6001600160a01b0316146125b95760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610996565b836001600160a01b0381163b61261c5760405162461bcd60e51b815260206004820152602260248201527f526571756972656d656e747352756c65733a206973206e6f7420636f6e74726160448201526118dd60f21b6064820152608401610996565b6000845111801561262d5750600083115b80156126395750600082115b80156126485750603e54845111155b6126945760405162461bcd60e51b815260206004820152601e60248201527f526571756972656d656e7452756c65733a20696e76616c6964206c69737400006044820152606401610996565b6001600160a01b0385166000908152604260209081526040909120855187926126c1929190880190614f61565b506001600160a01b0381166000908152604260205260409020600181018590556002018390556126f081612b86565b6127e357604454603f541161276d5760405162461bcd60e51b815260206004820152602a60248201527f526571756972656d656e747352756c65733a20636f6e7472616374734c696d6960448201527f74206578636565646564000000000000000000000000000000000000000000006064820152608401610996565b604480546001808201835560008390527f9b22d3d61959b4d3528b1d8ba932c96fbe302b36a1aad1d95cab54f9e0a135ea90910180546001600160a01b0319166001600160a01b03851617905590546127c69190615496565b6001600160a01b0382166000908152604260205260409020600301555b856001600160a01b03167f586adb7578e979f45e368cc35f5a22d692757ded182824b2c42923c3600ecd6986868660405161282093929190615346565b60405180910390a2505050505050565b612838614276565b6001600160a01b03166128536000546001600160a01b031690565b6001600160a01b0316146128a95760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610996565b866001600160a01b0381163b61290c5760405162461bcd60e51b815260206004820152602260248201527f526571756972656d656e747352756c65733a206973206e6f7420636f6e74726160448201526118dd60f21b6064820152608401610996565b600186151514801561291d57508651155b80156129295750600085115b80156129355750600084115b8061297157508515801561294a575060008751115b80156129565750600083115b80156129625750600082115b80156129715750603e54875111155b6129bd5760405162461bcd60e51b815260206004820152601e60248201527f526571756972656d656e7452756c65733a20696e76616c6964206c69737400006044820152606401610996565b86518890156129f1576001600160a01b038116600090815260416020908152604090912089516129ef928b0190614f61565b505b6001600160a01b038116600090815260416020526040902060028101879055600381018690556004810185905560058101849055600101805460ff1916881515179055612a3d816112d1565b612b3057604354603f5411612aba5760405162461bcd60e51b815260206004820152602a60248201527f526571756972656d656e747352756c65733a20636f6e7472616374734c696d6960448201527f74206578636565646564000000000000000000000000000000000000000000006064820152608401610996565b604380546001808201835560008390527f9690ad99d6ce244efa8a0f6c2d04036d3b33a9474db32a71b71135c69510279390910180546001600160a01b0319166001600160a01b0385161790559054612b139190615496565b6001600160a01b0382166000908152604160205260409020600601555b886001600160a01b03167fe41df969317a5283b930ab971b419d925fc5c58516b283b7bee55e29af3734fb898989898989604051612b739695949392919061530a565b60405180910390a2505050505050505050565b6044546000901580159061092f57506001600160a01b03821660008181526042602052604090206003015460448054909190811061131f57634e487b7160e01b600052603260045260246000fd5b60026045541415612c275760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610996565b6002604555612c3f604654600160a01b900460ff1690565b15612c7f5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610996565b612c87614276565b603c5415612d0357603c546001600160a01b0382166000908152603d6020526040902054612cb5919061544b565b4211612d035760405162461bcd60e51b815260206004820152601c60248201527f4c6f636b52756c65733a204465706f736974206d7573742077616974000000006044820152606401610996565b6001600160a01b0381166000908152603d60205260409020429055612d26614276565b8260036000612d33614276565b6001600160a01b03166001600160a01b03168152602001908152602001600020546000612d5f84610bfc565b90506000612d6c856116c7565b90506000612d7a8383614280565b90506000811180612d8c575060435415155b80612d98575060445415155b15612df65780612da8858761544b565b1115612df65760405162461bcd60e51b815260206004820152601d60248201527f526571756972656d656e747352756c65733a206d6178416c6c6f7765640000006044820152606401610996565b60008811612e465760405162461bcd60e51b815260206004820152601f60248201527f4552433230526577617264506f6f6c3a2043616e6e6f74207374616b652030006044820152606401610996565b60376000612e52614276565b6001600160a01b03168152602081019190915260400160002054612e98574260376000612e7d614276565b6001600160a01b031681526020810191909152604001600020555b42603d6000612ea5614276565b6001600160a01b03166001600160a01b03168152602001908152602001600020819055506000604d546000148015612ee75750604a546001600160a01b031615155b15612f7557604a60009054906101000a90046001600160a01b03166001600160a01b0316630572b0cc6040518163ffffffff1660e01b815260040160206040518083038186803b158015612f3a57600080fd5b505afa158015612f4e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f729190615278565b90505b612f806113f1614276565b612f8989614853565b612f94611412614276565b6000604e6000612fa2614276565b6001600160a01b03166001600160a01b0316815260200190815260200160002054116130365760405162461bcd60e51b815260206004820152602960248201527f4552433230526577617264506f6f6c3a206e6f7420656e6f75676820636f6e7460448201527f7269627574696f6e7300000000000000000000000000000000000000000000006064820152608401610996565b801561309b5780604c6000613049614276565b6001600160a01b03166001600160a01b0316815260200190815260200160002054613074919061544b565b604c6000613080614276565b6001600160a01b031681526020810191909152604001600020555b6130a3614276565b6001600160a01b03167f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d8a6040516130dd91815260200190565b60405180910390a25050600160455550505050505050565b600080805b6001600160a01b038516600090815260416020526040902054811015611f0b576001600160a01b03851660008181526041602052604081208054919291636352211e91908590811061315c57634e487b7160e01b600052603260045260246000fd5b90600052602060002001546040518263ffffffff1660e01b815260040161318591815260200190565b60206040518083038186803b15801561319d57600080fd5b505afa1580156131b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131d59190615071565b9050846001600160a01b0316816001600160a01b031614156131fd576131fa836154d9565b92505b5080613208816154d9565b9150506130fa565b816001600160a01b0381163b6132735760405162461bcd60e51b815260206004820152602260248201527f4552433230526577617264506f6f6c3a206973206e6f74206120636f6e74726160448201526118dd60f21b6064820152608401610996565b61327b614276565b6001600160a01b03166132966000546001600160a01b031690565b6001600160a01b0316146132ec5760405162461bcd60e51b815260206004820152601a60248201527f4552433230526577617264506f6f6c3a206e6f742061646d696e0000000000006044820152606401610996565b826001600160a01b0381166133435760405162461bcd60e51b815260206004820152601d60248201527f4552433230526577617264506f6f6c3a207a65726f20616464726573730000006044820152606401610996565b821561335157613351614931565b5050604a80546001600160a01b0319166001600160a01b03939093169290921790915550565b611578614931565b806001600160a01b0381163b6133e25760405162461bcd60e51b815260206004820152602260248201527f4552433230526577617264506f6f6c3a206973206e6f74206120636f6e74726160448201526118dd60f21b6064820152608401610996565b6133ea614276565b6001600160a01b03166134056000546001600160a01b031690565b6001600160a01b03161461345b5760405162461bcd60e51b815260206004820152601a60248201527f4552433230526577617264506f6f6c3a206e6f742061646d696e0000000000006044820152606401610996565b816001600160a01b0381166134b25760405162461bcd60e51b815260206004820152601d60248201527f4552433230526577617264506f6f6c3a207a65726f20616464726573730000006044820152606401610996565b5050604980546001600160a01b0319166001600160a01b0392909216919091179055565b6134de614276565b6001600160a01b03166134f96000546001600160a01b031690565b6001600160a01b03161461354f5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610996565b6040805482825581518381526020810182905290917fe71352959b0ea69ae334d4403e7b41245e1f9e6270d8664f4d2ae2477447785891016116bb565b6000613596614143565b604754611bbc919061544b565b6135ab614276565b6001600160a01b03166135c66000546001600160a01b031690565b6001600160a01b03161461361c5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610996565b62ed4e0081111561367b5760405162461bcd60e51b815260206004820152602360248201527f4c6f636b52756c65733a20696e76616c6964206c6f636b506572696f64496e5360448201526265637360e81b6064820152608401610996565b603c8190556040518181527fd5a5a9291a89dfff7924900a31224aa9b6afed79f5124add369f4a807f40f59790602001611cca565b6136b8614931565b60005b818110156137365760008383838181106136e557634e487b7160e01b600052603260045260246000fd5b90506020020160208101906136fa9190615055565b90506001600160a01b0381166137105750613724565b613719816149cd565b61372281614471565b505b8061372e816154d9565b9150506136bb565b505050565b806001600160a01b0381163b61379e5760405162461bcd60e51b815260206004820152602260248201527f4552433230526577617264506f6f6c3a206973206e6f74206120636f6e74726160448201526118dd60f21b6064820152608401610996565b6137a6614276565b6001600160a01b03166137c16000546001600160a01b031690565b6001600160a01b0316146138175760405162461bcd60e51b815260206004820152601a60248201527f4552433230526577617264506f6f6c3a206e6f742061646d696e0000000000006044820152606401610996565b50604680546001600160a01b0319166001600160a01b0392909216919091179055565b600080805b604354811015610eee5760008060006043848154811061386f57634e487b7160e01b600052603260045260246000fd5b60009182526020808320909101546001600160a01b03168083526041909152604090912060019081015491925060ff90911615151415613929576040516370a0823160e01b81526001600160a01b0388811660048301528216906370a082319060240160206040518083038186803b1580156138ea57600080fd5b505afa1580156138fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139229190615278565b9250613936565b61393381886130f5565b91505b6001600160a01b03811660009081526041602052604090206005015461395c9083615477565b6001600160a01b0382166000908152604160205260409020600301546139829085615477565b61398c919061544b565b613996908661544b565b945050505080806139a6906154d9565b91505061383f565b806001600160a01b038116613a055760405162461bcd60e51b815260206004820152601d60248201527f4552433230526577617264506f6f6c3a207a65726f20616464726573730000006044820152606401610996565b613a0e826142d6565b613a1782614471565b5050565b613a23614276565b6001600160a01b0316613a3e6000546001600160a01b031690565b6001600160a01b031614613a945760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610996565b613aa7604654600160a01b900460ff1690565b613af35760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610996565b806001600160a01b038116613b4a5760405162461bcd60e51b815260206004820152601d60248201527f4552433230526577617264506f6f6c3a207a65726f20616464726573730000006044820152606401610996565b6001546048546000916001600160a01b0391821691161415613bf5576002546048546040516370a0823160e01b81523060048201526001600160a01b03909116906370a082319060240160206040518083038186803b158015613bac57600080fd5b505afa158015613bc0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613be49190615278565b613bee9190615496565b9050613c73565b6048546040516370a0823160e01b81523060048201526001600160a01b03909116906370a082319060240160206040518083038186803b158015613c3857600080fd5b505afa158015613c4c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c709190615278565b90505b604854613736906001600160a01b03168483614a29565b60026045541415613cdd5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610996565b6002604555613cf5604654600160a01b900460ff1690565b15613d355760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610996565b613d406113f1614276565b613d7d613d4b614276565b60036000613d57614276565b6001600160a01b03166001600160a01b03168152602001908152602001600020546142e7565b613d886114e0614276565b613d93611412614276565b613d9b614276565b6001600160a01b03167f7c79e6e24ed041d1072d54523b53956f01b91b835f0490856370594d9d14470e60405160405180910390a26001604555565b613ddf614276565b6001600160a01b0316613dfa6000546001600160a01b031690565b6001600160a01b031614613e505760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610996565b6001600160a01b038116613ecc5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610996565b613ed581614ad2565b50565b613f036040518060800160405280606081526020016000815260200160008152602001600081525090565b816001600160a01b0381163b613f665760405162461bcd60e51b815260206004820152602260248201527f526571756972656d656e747352756c65733a206973206e6f7420636f6e74726160448201526118dd60f21b6064820152608401610996565b82613f7081612b86565b613fe25760405162461bcd60e51b815260206004820152602e60248201527f526571756972656d656e747352756c65733a20636f6e7472616374206973206e60448201527f6f7420696e20746865206c6973740000000000000000000000000000000000006064820152608401610996565b6001600160a01b0384166000908152604260209081526040918290208251815460a09381028201840190945260808101848152909391928492849184018282801561404c57602002820191906000526020600020905b815481526020019060010190808311614038575b50505050508152602001600182015481526020016002820154815260200160038201548152505092505050919050565b3b151590565b6046546000906001600160a01b031633141561413c57601836101561410f5760405162461bcd60e51b815260206004820152602260248201527f4552433237373148616e646c657256323a20496e76616c6964206d73672e646160448201527f74610000000000000000000000000000000000000000000000000000000000006064820152608401610996565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec36013560601c610f5b565b5033610f5b565b604a546000906001600160a01b0316158061415e5750604d54155b1561416b57506000610f5b565b604d54604a60009054906101000a90046001600160a01b03166001600160a01b0316630572b0cc6040518163ffffffff1660e01b815260040160206040518083038186803b1580156141bc57600080fd5b505afa1580156141d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141f49190615278565b6142089069d3c21bcecceda1000000615477565b611bbc9190615463565b6001600160a01b0382166000908152604e6020908152604080832054604b90925282205460475469d3c21bcecceda1000000929190614251908661544b565b61425b9190615496565b6142659190615477565b61426f9190615463565b9392505050565b6000611bbc614082565b60405460009081614291848661544b565b11156142cb57604054156142b9576142b2816142ad858761544b565b614b22565b90506142c6565b6142c3838561544b565b90505b61426f565b506040549392505050565b6142de614931565b613ed5816149cd565b6142ef614276565b603a541561436b57603a546001600160a01b0382166000908152603b602052604090205461431d919061544b565b421161436b5760405162461bcd60e51b815260206004820152601d60248201527f4c6f636b52756c65733a205769746864726177206d75737420776169740000006044820152606401610996565b6001600160a01b0381166000908152603b60205260409020429055816143f95760405162461bcd60e51b815260206004820152602260248201527f4552433230526577617264506f6f6c3a2043616e6e6f7420776974686472617760448201527f20300000000000000000000000000000000000000000000000000000000000006064820152608401610996565b42603b6000614406614276565b6001600160a01b0316815260208101919091526040016000205561442982614b38565b826001600160a01b03167f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d58360405161446491815260200190565b60405180910390a2505050565b6001600160a01b0381166000908152604e6020526040902054604d54614498908290615496565b604d5560006144a683614c15565b905080604d546144b6919061544b565b604d556001600160a01b0383166000818152604e602090815260409182902084905581518481529081018590527f36c7c98dfe7e045d8de3e3a8ef7280d623eeb82e7ac5f92d4854297dd07813059101614464565b603654819015614589576036546001600160a01b03821660009081526037602052604090205461453b919061544b565b42116145895760405162461bcd60e51b815260206004820152601a60248201527f4c6f636b52756c65733a20436c61696d206d75737420776169740000000000006044820152606401610996565b6001600160a01b0380821660009081526037602090815260408083204290559285168252604c9052908120549081156146d65760395460ff16151560011415614667576145de670de0b6b3a7640000836154f4565b90506145ea8183615496565b91508160386000015411156146675760405162461bcd60e51b815260206004820152603c60248201527f4552433230526577617264506f6f6c3a2043616e6e6f7420776974686472617760448201527f202d206c6f636b436c61696d2e616d6f756e74203c20726577617264000000006064820152608401610996565b6001600160a01b038085166000908152604c6020526040902082905560485461469291168584614a29565b836001600160a01b03167fe2403640ba68fed3a2f88b7557551d1993f84b99bb10ff833f0cf8db0c5e0486836040516146cd91815260200190565b60405180910390a25b50505050565b6146ef604654600160a01b900460ff1690565b61473b5760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610996565b604680547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa61478c614276565b6040516001600160a01b03909116815260200160405180910390a1565b6147bc604654600160a01b900460ff1690565b156147fc5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610996565b604680547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861478c614276565b600081116148a35760405162461bcd60e51b815260206004820152601d60248201527f5374616b65546f6b656e577261707065723a20616d6f756e74203e20300000006044820152606401610996565b806002546148b1919061544b565b60025580600360006148c1614276565b6001600160a01b03166001600160a01b03168152602001908152602001600020546148ec919061544b565b600360006148f8614276565b6001600160a01b03168152602081019190915260400160002055613ed561491d614276565b6001546001600160a01b0316903084614d20565b604a546001600160a01b0316156115785761494a614143565b604754614957919061544b565b604755604a54604080517fb016584000000000000000000000000000000000000000000000000000000000815290516001600160a01b039092169163b01658409160048082019260009290919082900301818387803b1580156149b957600080fd5b505af11580156146d6573d6000803e3d6000fd5b6149d8816000614212565b6001600160a01b0382166000908152604c60205260409020546149fb919061544b565b6001600160a01b039091166000908152604c6020908152604080832093909355604754604b90915291902055565b6040516001600160a01b0383166024820152604481018290526137369084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152614d71565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000818310614b31578161426f565b5090919050565b60008111614b885760405162461bcd60e51b815260206004820152601d60248201527f5374616b65546f6b656e577261707065723a20616d6f756e74203e20300000006044820152606401610996565b80600254614b969190615496565b6002558060036000614ba6614276565b6001600160a01b03166001600160a01b0316815260200190815260200160002054614bd19190615496565b60036000614bdd614276565b6001600160a01b03168152602081019190915260400160002055613ed5614c02614276565b6001546001600160a01b03169083614a29565b6049546000906001600160a01b0316614c55576001600160a01b038216600090815260036020526040902054614c4e906142ad84610f5e565b9050610932565b6049546001600160a01b03838116600090815260036020526040902054911690633f6f66f5908490614c8a906142ad83610f5e565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381600087803b158015614ce857600080fd5b505af1158015614cfc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614c4e9190615278565b6040516001600160a01b03808516602483015283166044820152606481018290526146d69085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401614a6e565b6000614dc6826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614e569092919063ffffffff16565b8051909150156137365780806020019051810190614de49190615217565b6137365760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610996565b6060610f83848460008585843b614eaf5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610996565b600080866001600160a01b03168587604051614ecb91906152ee565b60006040518083038185875af1925050503d8060008114614f08576040519150601f19603f3d011682016040523d82523d6000602084013e614f0d565b606091505b5091509150614f1d828286614f28565b979650505050505050565b60608315614f3757508161426f565b825115614f475782518084602001fd5b8160405162461bcd60e51b8152600401610996919061536b565b828054828255906000526020600020908101928215614f9c579160200282015b82811115614f9c578251825591602001919060010190614f81565b50610f599291505b80821115610f595760008155600101614fa4565b600082601f830112614fc8578081fd5b8135602067ffffffffffffffff80831115614fe557614fe5615534565b818302604051601f19603f8301168101818110848211171561500957615009615534565b60405284815283810192508684018288018501891015615027578687fd5b8692505b8583101561504957803584529284019260019290920191840161502b565b50979650505050505050565b600060208284031215615066578081fd5b813561426f8161554a565b600060208284031215615082578081fd5b815161426f8161554a565b600080600080600080600060e0888a0312156150a7578283fd5b87356150b28161554a565b9650602088013567ffffffffffffffff8111156150cd578384fd5b6150d98a828b01614fb8565b96505060408801356150ea8161555f565b969995985095966060810135965060808101359560a0820135955060c0909101359350915050565b60008060008060808587031215615127578384fd5b84356151328161554a565b9350602085013567ffffffffffffffff81111561514d578384fd5b61515987828801614fb8565b949794965050505060408301359260600135919050565b60008060408385031215615182578182fd5b823561518d8161554a565b9150602083013561519d8161555f565b809150509250929050565b600080602083850312156151ba578182fd5b823567ffffffffffffffff808211156151d1578384fd5b818501915085601f8301126151e4578384fd5b8135818111156151f2578485fd5b8660208083028501011115615205578485fd5b60209290920196919550909350505050565b600060208284031215615228578081fd5b815161426f8161555f565b60008060408385031215615245578182fd5b82356152508161554a565b9150602083013561519d8161554a565b600060208284031215615271578081fd5b5035919050565b600060208284031215615289578081fd5b5051919050565b600080604083850312156152a2578182fd5b82359150602083013561519d8161555f565b6000815180845260208085019450808401835b838110156152e3578151875295820195908201906001016152c7565b509495945050505050565b600082516153008184602087016154ad565b9190910192915050565b600060c0825261531d60c08301896152b4565b96151560208301525060408101949094526060840192909252608083015260a090910152919050565b60006060825261535960608301866152b4565b60208301949094525060400152919050565b600060208252825180602084015261538a8160408501602087016154ad565b601f01601f19169190910160400192915050565b6000602082528251608060208401526153ba60a08401826152b4565b90506020840151604084015260408401516060840152606084015160808401528091505092915050565b600060208252825160e060208401526154016101008401826152b4565b90506020840151151560408401526040840151606084015260608401516080840152608084015160a084015260a084015160c084015260c084015160e08401528091505092915050565b6000821982111561545e5761545e615508565b500190565b6000826154725761547261551e565b500490565b600081600019048311821515161561549157615491615508565b500290565b6000828210156154a8576154a8615508565b500390565b60005b838110156154c85781810151838201526020016154b0565b838111156146d65750506000910152565b60006000198214156154ed576154ed615508565b5060010190565b6000826155035761550361551e565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114613ed557600080fd5b8015158114613ed557600080fdfea2646970667358221220452ecd35109392d8c81658cb199f2ae3251635d309051f052a2d18f527c9ad5864736f6c63430008020033000000000000000000000000bbba073c31bf03b8acf7c28ef0738decf3695683000000000000000000000000bbba073c31bf03b8acf7c28ef0738decf3695683000000000000000000000000f0511f123164602042ab2bcf02111fa5d3fe97cd
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000bbba073c31bf03b8acf7c28ef0738decf3695683000000000000000000000000bbba073c31bf03b8acf7c28ef0738decf3695683000000000000000000000000f0511f123164602042ab2bcf02111fa5d3fe97cd
-----Decoded View---------------
Arg [0] : stakeToken_ (address): 0xbbba073c31bf03b8acf7c28ef0738decf3695683
Arg [1] : rewardToken_ (address): 0xbbba073c31bf03b8acf7c28ef0738decf3695683
Arg [2] : trustedForwarder (address): 0xf0511f123164602042ab2bcf02111fa5d3fe97cd
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000bbba073c31bf03b8acf7c28ef0738decf3695683
Arg [1] : 000000000000000000000000bbba073c31bf03b8acf7c28ef0738decf3695683
Arg [2] : 000000000000000000000000f0511f123164602042ab2bcf02111fa5d3fe97cd
Age | Block | Fee Address | BC Fee Address | Voting Power | Jailed | Incoming |
---|
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.