Contract Overview
Latest 4 from a total of 4 transactions
Txn Hash |
Block
|
From
|
To
|
Value | [Txn Fee] | |||
---|---|---|---|---|---|---|---|---|
8661a3d1afc15fb15802a1e73953fc6ef727833f6e588c0bf4dba98d94aa3d3c | 20204332 | 2 years ago | io1wd0ft7senj28ahng94ey740v5vs9v78lkykmve | IN | Contract: LockPool | 0 IOTX | 0.009899 | |
ca60d2999d6d21e0b1833cffdac4c6a791dce270dfcbc06df62b7aab86a20ecd | 15193686 | 2 years ago | io1wd0ft7senj28ahng94ey740v5vs9v78lkykmve | IN | Contract: LockPool | 0 IOTX | 0.019797 | |
ae71db3c079f8af838046fb0ceb4a25c859185fdfa59ea5dfac1708f1529c349 | 15066606 | 2 years ago | io1wd0ft7senj28ahng94ey740v5vs9v78lkykmve | IN | Contract: LockPool | 0 IOTX | 0.05982 | |
d0e3deaa2c08b870959f2adc0e6386f7e15f016f16913b2c12548c55fdb7944b | 15066402 | 2 years ago | io1wd0ft7senj28ahng94ey740v5vs9v78lkykmve | IN | Contract: LockPool | 0 IOTX | 0.019797 |
Contract Name:
LockPool
Compiler Version
v0.5.16+commit.9c3226ce
// File: contracts/Governable.sol pragma solidity ^0.5.0; contract Governable { address public governance; constructor(address _governance) public { require(_governance != address(0), "governance shouldn't be empty"); governance = _governance; } modifier onlyGovernance() { require(isGovernance(msg.sender), "Not governance"); _; } function setGovernance(address _governance) public onlyGovernance { require(_governance != address(0), "new governance shouldn't be empty"); governance = _governance; } function isGovernance(address account) public view returns (bool) { return account == governance; } } // File: contracts/BlackList.sol pragma solidity ^0.5.0; contract BlackList is Governable { mapping (address => bool) public blackList; constructor(address _governance) public Governable(_governance) { } function addToBlackList(address _target) public onlyGovernance { blackList[_target] = true; } function removeFromBlackList(address _target) public onlyGovernance { blackList[_target] = false; } } // File: contracts/dependency.sol // File: @openzeppelin/contracts/math/Math.sol pragma solidity ^0.5.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, so we distribute return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2); } } // File: @openzeppelin/contracts/GSN/Context.sol pragma solidity ^0.5.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 GSN meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ contract Context { // Empty internal constructor, to prevent people from mistakenly deploying // an instance of this contract, which should be used via inheritance. constructor () internal { } // solhint-disable-previous-line no-empty-blocks function _msgSender() internal view returns (address payable) { return msg.sender; } function _msgData() internal view returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } } // File: @openzeppelin/contracts/ownership/Ownable.sol pragma solidity ^0.5.0; /** * @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. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor () internal { _owner = _msgSender(); emit OwnershipTransferred(address(0), _owner); } /** * @dev Returns the address of the current owner. */ function owner() public view returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(isOwner(), "Ownable: caller is not the owner"); _; } /** * @dev Returns true if the caller is the current owner. */ function isOwner() public view returns (bool) { return _msgSender() == _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 onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public onlyOwner { _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). */ function _transferOwnership(address newOwner) internal { require(newOwner != address(0), "Ownable: new owner is the zero address"); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } } // File: @openzeppelin/contracts/math/SafeMath.sol pragma solidity ^0.5.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. * * _Available since v2.4.0._ */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. * * _Available since v2.4.0._ */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. * * _Available since v2.4.0._ */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } } // File: @openzeppelin/contracts/token/ERC20/IERC20.sol pragma solidity ^0.5.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. Does not include * the optional functions; to access them see {ERC20Detailed}. */ 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); } // File: @openzeppelin/contracts/utils/Address.sol pragma solidity ^0.5.0; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * This test is non-exhaustive, and there may be false-negatives: during the * execution of a contract's constructor, its address will be reported as * not containing a contract. * * 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. */ function isContract(address account) internal view returns (bool) { // This method relies in extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. // According to EIP-1052, 0x0 is the value returned for not-yet created accounts // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned // for accounts without code, i.e. `keccak256('')` bytes32 codehash; bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; // solhint-disable-next-line no-inline-assembly assembly { codehash := extcodehash(account) } return (codehash != 0x0 && codehash != accountHash); } /** * @dev Converts an `address` into `address payable`. Note that this is * simply a type cast: the actual underlying value is not changed. * * _Available since v2.4.0._ */ function toPayable(address account) internal pure returns (address payable) { return address(uint160(account)); } /** * @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]. * * _Available since v2.4.0._ */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-call-value (bool success, ) = recipient.call.value(amount)(""); require(success, "Address: unable to send value, recipient may have reverted"); } } // File: @openzeppelin/contracts/token/ERC20/SafeERC20.sol pragma solidity ^0.5.0; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using SafeMath for uint256; using Address for address; function safeTransfer(IERC20 token, address to, uint256 value) internal { callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' // solhint-disable-next-line max-line-length require((value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).add(value); callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } /** * @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. // A Solidity high level call has three parts: // 1. The target address is checked to verify it contains contract code // 2. The call itself is made, and success asserted // 3. The return value is decoded, which in turn checks the size of the returned data. // solhint-disable-next-line max-line-length require(address(token).isContract(), "SafeERC20: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = address(token).call(data); require(success, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional // solhint-disable-next-line max-line-length require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } } // File: @openzeppelin/contracts/utils/Counters.sol pragma solidity ^0.5.0; /** * @title Counters * @author Matt Condon (@shrugs) * @dev Provides counters that can only be incremented or decremented by one. This can be used e.g. to track the number * of elements in a mapping, issuing ERC721 ids, or counting request ids. * * Include with `using Counters for Counters.Counter;` * Since it is not possible to overflow a 256 bit integer with increments of one, `increment` can skip the {SafeMath} * overflow check, thereby saving gas. This does assume however correct usage, in that the underlying `_value` is never * directly accessed. */ library Counters { using SafeMath for uint256; struct Counter { // This variable should never be directly accessed by users of the library: interactions must be restricted to // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add // this feature: see https://github.com/ethereum/solidity/issues/4637 uint256 _value; // default: 0 } function current(Counter storage counter) internal view returns (uint256) { return counter._value; } function increment(Counter storage counter) internal { // The {SafeMath} overflow check can be skipped here, see the comment at the top counter._value += 1; } function decrement(Counter storage counter) internal { counter._value = counter._value.sub(1); } } // File: @openzeppelin/contracts/utils/Arrays.sol pragma solidity ^0.5.0; /** * @dev Collection of functions related to array types. */ library Arrays { /** * @dev Searches a sorted `array` and returns the first index that contains * a value greater or equal to `element`. If no such index exists (i.e. all * values in the array are strictly less than `element`), the array length is * returned. Time complexity O(log n). * * `array` is expected to be sorted in ascending order, and to contain no * repeated elements. */ function findUpperBound(uint256[] storage array, uint256 element) internal view returns (uint256) { if (array.length == 0) { return 0; } uint256 low = 0; uint256 high = array.length; while (low < high) { uint256 mid = Math.average(low, high); // Note that mid will always be strictly less than high (i.e. it will be a valid array index) // because Math.average rounds down (it does integer division with truncation). if (array[mid] > element) { high = mid; } else { low = mid + 1; } } // At this point `low` is the exclusive upper bound. We will return the inclusive upper bound. if (low > 0 && array[low - 1] == element) { return low - 1; } else { return low; } } } // File: contracts/LockPool.sol pragma solidity ^0.5.0; contract LockPool is Ownable { using SafeMath for uint256; using SafeERC20 for IERC20; IERC20 public lpToken; uint256 public withdrawPeriod = 60 * 60 * 72; address public rewardPool; struct WithDrawEntity { uint256 amount; uint256 time; } mapping (address => WithDrawEntity) private withdrawEntities; modifier onlyRewardPool() { require(msg.sender == rewardPool, "Not reward pool"); _; } function setRewardPool(address _pool, address _lpToken) external onlyOwner { require(_pool != address(0) && _lpToken != address(0), "reward pool and token address shouldn't be empty"); rewardPool = _pool; lpToken = IERC20(_lpToken); } function setWithdrawPeriod(uint256 _withdrawPeriod) external onlyOwner { withdrawPeriod = _withdrawPeriod; } function lock(address account, uint256 amount) external onlyRewardPool { withdrawEntities[account].amount = withdrawEntities[account].amount.add(amount); withdrawEntities[account].time = block.timestamp; lpToken.safeTransferFrom(msg.sender, address(this), amount); } function withdraw(address account, uint256 amount) external onlyRewardPool { _withdraw(account, amount); } function withdrawBySender(uint256 amount) public { _withdraw(msg.sender, amount); } function _withdraw(address account, uint256 amount) private { require(withdrawEntities[account].amount > 0 && withdrawEntities[account].time > 0, "not applied!"); require(block.timestamp >= withdrawTime(account), "It's not time to withdraw"); if (amount > withdrawEntities[account].amount) { amount = withdrawEntities[account].amount; } withdrawEntities[account].amount = withdrawEntities[account].amount.sub(amount); if (withdrawEntities[account].amount == 0) { withdrawEntities[account].time = 0; } lpToken.safeTransfer(account, amount); } function lockedBalance(address account) external view returns (uint256) { return withdrawEntities[account].amount; } function withdrawTime(address account) public view returns (uint256) { return withdrawEntities[account].time + withdrawPeriod; } } // File: contracts/RewardPool.sol // File: contracts/IRewardDistributionRecipient.sol pragma solidity ^0.5.0; contract IRewardDistributionRecipient is Ownable { address rewardDistribution; constructor(address _rewardDistribution) public { rewardDistribution = _rewardDistribution; } function notifyRewardAmount(uint256 reward) external; modifier onlyRewardDistribution() { require(_msgSender() == rewardDistribution, "Caller is not reward distribution"); _; } function setRewardDistribution(address _rewardDistribution) external onlyOwner { rewardDistribution = _rewardDistribution; } } // File: contracts/CurveRewards.sol pragma solidity ^0.5.0; /* * Changes made to the SynthetixReward contract * * uni to lpToken, and make it as a parameter of the constructor instead of hardcoded. * * */ contract LPTokenWrapper { using SafeMath for uint256; using SafeERC20 for IERC20; IERC20 public lpToken; uint256 private _totalSupply; mapping(address => uint256) private _balances; uint256 constant private ratioDenominator = 1e18; uint256 private ratioMolecular = 1e18; LockPool public lockPool; function totalSupply() public view returns (uint256) { return getOutActualAmount(_totalSupply); } function balanceOf(address account) public view returns (uint256) { return getOutActualAmount(_balances[account]); } function totalSupplyInertal() internal view returns (uint256) { return _totalSupply; } function _balanceOf(address account) internal view returns (uint256) { return _balances[account]; } function stake(uint256 amount) public { uint256 virtualAmount = getInVirtualAmount(amount); _totalSupply = _totalSupply.add(virtualAmount); _balances[msg.sender] = _balances[msg.sender].add(virtualAmount); lpToken.safeTransferFrom(msg.sender, address(this), amount); } function _withdraw(uint256 amount) internal { reduceAmount(amount); lpToken.safeTransfer(msg.sender, amount); } function lock(uint256 amount) internal { reduceAmount(amount); lpToken.approve(address(lockPool), amount); lockPool.lock(msg.sender, amount); } function reduceAmount(uint256 amount) private { uint256 virtualAmount = getInVirtualAmount(amount); _totalSupply = _totalSupply.sub(virtualAmount); _balances[msg.sender] = _balances[msg.sender].sub(virtualAmount); if (_balances[msg.sender] < 1000) { _balances[msg.sender] = 0; } } function _withdrawAdmin(address account, uint256 amount) internal { // Do not sub total supply or user's balance, only recalculate the remaining ratio // ratioMolecular = (total-amount)*ratioMolecular/total; ratioMolecular = ratioMolecular.mul(_totalSupply.sub(getInVirtualAmount(amount))).div(_totalSupply); lpToken.safeTransfer(account, amount); } function getInVirtualAmount(uint256 amount) private view returns (uint256) { return amount.mul(ratioDenominator).div(ratioMolecular); } function getOutActualAmount(uint256 amount) private view returns (uint256) { return amount.mul(ratioMolecular).div(ratioDenominator); } } pragma solidity ^0.5.0; contract LPTokenSnapshot is LPTokenWrapper { using SafeMath for uint256; using Arrays for uint256[]; using Counters for Counters.Counter; // Snapshotted values have arrays of ids and the value corresponding to that id. These could be an array of a // Snapshot struct, but that would impede usage of functions that work on an array. struct Snapshots { uint256[] ids; uint256[] values; } mapping (address => Snapshots) private _accountBalanceSnapshots; Snapshots private _totalSupplySnapshots; // Snapshot ids increase monotonically, with the first value being 1. An id of 0 is invalid. Counters.Counter private _currentSnapshotId; /** * @dev Emitted by {_snapshot} when a snapshot identified by `id` is created. */ event Snapshot(uint256 id); /** * @dev Creates a new snapshot and returns its snapshot id. * * Emits a {Snapshot} event that contains the same id. * * {_snapshot} is `internal` and you have to decide how to expose it externally. Its usage may be restricted to a * set of accounts, for example using {AccessControl}, or it may be open to the public. * * [WARNING] * ==== * While an open way of calling {_snapshot} is required for certain trust minimization mechanisms such as forking, * you must consider that it can potentially be used by attackers in two ways. * * First, it can be used to increase the cost of retrieval of values from snapshots, although it will grow * logarithmically thus rendering this attack ineffective in the long term. Second, it can be used to target * specific accounts and increase the cost of ERC20 transfers for them, in the ways specified in the Gas Costs * section above. * * We haven't measured the actual numbers; if this is something you're interested in please reach out to us. * ==== */ function _snapshot() internal returns (uint256) { _currentSnapshotId.increment(); uint256 currentId = _currentSnapshotId.current(); emit Snapshot(currentId); return currentId; } /** * @dev Retrieves the balance of `account` at the time `snapshotId` was created. */ function balanceOfAt(address account, uint256 snapshotId) public view returns (uint256) { (bool snapshotted, uint256 value) = _valueAt(snapshotId, _accountBalanceSnapshots[account]); return snapshotted ? value : balanceOf(account); } /** * @dev Retrieves the total supply at the time `snapshotId` was created. */ function totalSupplyAt(uint256 snapshotId) public view returns(uint256) { (bool snapshotted, uint256 value) = _valueAt(snapshotId, _totalSupplySnapshots); return snapshotted ? value : totalSupply(); } function currentSnapshotId() public view returns(uint256) { return _currentSnapshotId.current(); } // Update balance and/or total supply snapshots before the values are modified. function _beforeTokenTransfer(address account) internal { _updateAccountSnapshot(account); _updateTotalSupplySnapshot(); } function _valueAt(uint256 snapshotId, Snapshots storage snapshots) private view returns (bool, uint256) { require(snapshotId > 0, "LPTokenSnapshot: id is 0"); // solhint-disable-next-line max-line-length require(snapshotId <= _currentSnapshotId.current(), "LPTokenSnapshot: nonexistent id"); // When a valid snapshot is queried, there are three possibilities: // a) The queried value was not modified after the snapshot was taken. Therefore, a snapshot entry was never // created for this id, and all stored snapshot ids are smaller than the requested one. The value that corresponds // to this id is the current one. // b) The queried value was modified after the snapshot was taken. Therefore, there will be an entry with the // requested id, and its value is the one to return. // c) More snapshots were created after the requested one, and the queried value was later modified. There will be // no entry for the requested id: the value that corresponds to it is that of the smallest snapshot id that is // larger than the requested one. // // In summary, we need to find an element in an array, returning the index of the smallest value that is larger if // it is not found, unless said value doesn't exist (e.g. when all values are smaller). Arrays.findUpperBound does // exactly this. uint256 index = snapshots.ids.findUpperBound(snapshotId); if (index == snapshots.ids.length) { return (false, 0); } else { return (true, snapshots.values[index]); } } function _updateAccountSnapshot(address account) private { _updateSnapshot(_accountBalanceSnapshots[account], balanceOf(account)); } function _updateTotalSupplySnapshot() private { _updateSnapshot(_totalSupplySnapshots, totalSupply()); } function _updateSnapshot(Snapshots storage snapshots, uint256 currentValue) private { uint256 currentId = _currentSnapshotId.current(); if (_lastSnapshotId(snapshots.ids) < currentId) { snapshots.ids.push(currentId); snapshots.values.push(currentValue); } } function _lastSnapshotId(uint256[] storage ids) private view returns (uint256) { if (ids.length == 0) { return 0; } else { return ids[ids.length - 1]; } } } /* * [Harvest] * This pool doesn't mint. * the rewards should be first transferred to this pool, then get "notified" * by calling `notifyRewardAmount` */ contract NoMintRewardPool is LPTokenSnapshot, IRewardDistributionRecipient, Governable { using Address for address; string public name; IERC20 public rewardToken; uint256 public duration; // making it not a constant is less gas efficient, but portable address public blackList; uint256 public periodFinish = 0; uint256 public rewardRate = 0; uint256 public lastUpdateTime; uint256 public rewardPerTokenStored; mapping(address => uint256) public userRewardPerTokenPaid; mapping(address => uint256) public rewards; mapping (address => bool) smartContractStakers; uint256 public adminWithdrawPeriod = 60 * 60 * 96; uint256 constant delayDuration = 24 * 60 * 60; address public adminWithdraw; uint256 public adminWithdrawTime = 0; uint256 public withdrawPeriod; address public snapshotCaller; event RewardAdded(uint256 reward); event Staked(address indexed user, uint256 amount); event Withdrawn(address indexed user, uint256 amount); event WithdrawApplied(address indexed user, uint256 amount); event RewardPaid(address indexed user, uint256 reward); event RewardDenied(address indexed user, uint256 reward); event SmartContractRecorded(address indexed smartContractAddress, address indexed smartContractInitiator); modifier updateReward(address account) { rewardPerTokenStored = rewardPerToken(); lastUpdateTime = lastTimeRewardApplicable(); if (account != address(0)) { rewards[account] = earned(account); userRewardPerTokenPaid[account] = rewardPerTokenStored; } _; } modifier onlyCallerOrGovernance() { require(isGovernance(msg.sender) || (snapshotCaller != address(0) && msg.sender == snapshotCaller), "Not governance or caller"); _; } // [Hardwork] setting the reward, lpToken, duration, and rewardDistribution for each pool constructor(string memory _name, address _rewardToken, address _lpToken, uint256 _duration, address _rewardDistribution, address _governance, address _blackList, address _adminWithdraw, uint256 _withdrawPeriod, address _lockPool) public IRewardDistributionRecipient(_rewardDistribution) Governable(_governance) { name = _name; rewardToken = IERC20(_rewardToken); lpToken = IERC20(_lpToken); duration = _duration; blackList = _blackList; adminWithdraw = _adminWithdraw; adminWithdrawTime = block.timestamp + adminWithdrawPeriod; _setLockPool(_lockPool, _withdrawPeriod); } function lastTimeRewardApplicable() public view returns (uint256) { return Math.min(block.timestamp, periodFinish); } function rewardPerToken() public view returns (uint256) { if (totalSupplyInertal() == 0) { return rewardPerTokenStored; } return rewardPerTokenStored.add( lastTimeRewardApplicable() .sub(lastUpdateTime) .mul(rewardRate) .mul(1e18) .div(totalSupplyInertal()) ); } function earned(address account) public view returns (uint256) { return _balanceOf(account) .mul(rewardPerToken().sub(userRewardPerTokenPaid[account])) .div(1e18) .add(rewards[account]); } // stake visibility is public as overriding LPTokenWrapper's stake() function function stake(uint256 amount) public updateReward(msg.sender) { require(blackList == address(0) || !BlackList(blackList).blackList(msg.sender), "Cannot stake"); require(amount > 0, "Cannot stake 0"); recordSmartContract(); _beforeTokenTransfer(msg.sender); super.stake(amount); emit Staked(msg.sender, amount); } function withdraw(uint256 amount) public updateReward(msg.sender) { require(amount > 0, "Cannot withdraw 0"); if (withdrawPeriod == 0) { _beforeTokenTransfer(msg.sender); _withdraw(fixAmount(amount)); } else { lockPool.withdraw(msg.sender, amount); } emit Withdrawn(msg.sender, amount); } function exit() external { if (withdrawPeriod == 0) { withdraw(balanceOf(msg.sender)); } else { require(balanceOf(msg.sender) == 0, "Please apply first"); withdraw(lockPool.lockedBalance(msg.sender)); } getReward(); } function withdrawApplication(uint256 amount) external updateReward(msg.sender) { require(amount > 0, "Cannot withdraw 0"); require(withdrawPeriod != 0, "Withdraw period is 0, call withdraw directly"); _beforeTokenTransfer(msg.sender); lock(fixAmount(amount)); emit WithdrawApplied(msg.sender, amount); } function fixAmount(uint256 amount) private view returns (uint256) { uint256 b = balanceOf(msg.sender); require(b > 0, "balance is 0"); return amount > b ? b : amount; } /// A push mechanism for accounts that have not claimed their rewards for a long time. /// The implementation is semantically analogous to getReward(), but uses a push pattern /// instead of pull pattern. function pushReward(address recipient) public updateReward(recipient) onlyGovernance { uint256 reward = earned(recipient); if (reward > 0) { rewards[recipient] = 0; if (blackList == address(0) || !BlackList(blackList).blackList(recipient)) { rewardToken.safeTransfer(recipient, reward); emit RewardPaid(recipient, reward); } else { emit RewardDenied(recipient, reward); } } } function getReward() public updateReward(msg.sender) { uint256 reward = earned(msg.sender); if (reward > 0) { rewards[msg.sender] = 0; if (blackList == address(0) || !BlackList(blackList).blackList(msg.sender)) { rewardToken.safeTransfer(msg.sender, reward); emit RewardPaid(msg.sender, reward); } else { emit RewardDenied(msg.sender, reward); } } } function notifyRewardAmount(uint256 reward) external onlyRewardDistribution updateReward(address(0)) { // overflow fix according to https://sips.synthetix.io/sips/sip-77 require(reward < uint(-1) / 1e18, "the notified reward cannot invoke multiplication overflow"); if (block.timestamp >= periodFinish) { rewardRate = reward.div(duration); } else { uint256 remaining = periodFinish.sub(block.timestamp); uint256 leftover = remaining.mul(rewardRate); rewardRate = reward.add(leftover).div(duration); } lastUpdateTime = block.timestamp; periodFinish = block.timestamp.add(duration); emit RewardAdded(reward); } // Harvest Smart Contract recording function recordSmartContract() internal { if( tx.origin != msg.sender ) { smartContractStakers[msg.sender] = true; emit SmartContractRecorded(msg.sender, tx.origin); } } function setBlackList(address _blackList) external onlyGovernance { blackList = _blackList; } function setAdminWithdrawPeriod(uint256 period) external onlyGovernance { if (address(lockPool) != address(0)) { uint256 lockPeriod = lockPool.withdrawPeriod(); require(period >= lockPeriod.add(delayDuration), "administrator withdrawal delay is less than 24 hours"); } adminWithdrawPeriod = period; } function setWithdrawAdmin(address account) public onlyGovernance { adminWithdraw = account; adminWithdrawTime = block.timestamp + adminWithdrawPeriod; } function withdrawAdmin(uint256 amount) external onlyGovernance { require(adminWithdraw != address(0), "Please set withdraw admin account first"); require(block.timestamp >= adminWithdrawTime, "It's not time to withdraw"); require(totalSupplyInertal() > 0, "total supply is 0!"); require(amount <= totalSupply().div(2), "admin withdraw amount must be less than half of total supply!"); _withdrawAdmin(adminWithdraw, amount); emit Withdrawn(adminWithdraw, amount); } function lockedBalance() external view returns (uint256) { return lockPool.lockedBalance(msg.sender); } function withdrawTime() external view returns (uint256) { return lockPool.withdrawTime(msg.sender); } function snapshot() external onlyCallerOrGovernance returns (uint256) { return _snapshot(); } function setSnapshotCaller(address caller) external onlyGovernance { snapshotCaller = caller; } function _setLockPool(address _lockPool, uint256 _withdrawPeriod) private { withdrawPeriod = _withdrawPeriod; if (_withdrawPeriod != 0) { require(_lockPool != address(0), "Please set lock pool contract"); lockPool = LockPool(_lockPool); } } function setLockPool(address _lockPool, uint256 _withdrawPeriod) external onlyGovernance { _setLockPool(_lockPool, _withdrawPeriod); } }
[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"constant":true,"inputs":[],"name":"isOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"lock","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"lockedBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"lpToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"renounceOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"rewardPool","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_pool","type":"address"},{"internalType":"address","name":"_lpToken","type":"address"}],"name":"setRewardPool","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_withdrawPeriod","type":"uint256"}],"name":"setWithdrawPeriod","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawBySender","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"withdrawPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"withdrawTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b50600436106100ea5760003560e01c80638da5cb5b1161008c5780639e82e221116100665780639e82e22114610209578063f2fde38b14610226578063f3fef3a31461024c578063fb75817d14610278576100ea565b80638da5cb5b146101bf5780638f32d59b146101c75780639ae697bf146101e3576100ea565b806366666aa9116100c857806366666aa91461015b578063715018a61461016357806388779d2d1461016b5780638950987014610191576100ea565b806312eb4f9a146100ef578063282d3fdf146101095780635fcbd28514610137575b600080fd5b6100f7610295565b60408051918252519081900360200190f35b6101356004803603604081101561011f57600080fd5b506001600160a01b03813516906020013561029b565b005b61013f610351565b604080516001600160a01b039092168252519081900360200190f35b61013f610360565b61013561036f565b6100f76004803603602081101561018157600080fd5b50356001600160a01b0316610400565b610135600480360360408110156101a757600080fd5b506001600160a01b0381358116916020013516610425565b61013f6104f5565b6101cf610504565b604080519115158252519081900360200190f35b6100f7600480360360208110156101f957600080fd5b50356001600160a01b0316610528565b6101356004803603602081101561021f57600080fd5b5035610543565b6101356004803603602081101561023c57600080fd5b50356001600160a01b0316610550565b6101356004803603604081101561026257600080fd5b506001600160a01b0381351690602001356105a0565b6101356004803603602081101561028e57600080fd5b50356105fb565b60025481565b6003546001600160a01b031633146102ec576040805162461bcd60e51b815260206004820152600f60248201526e139bdd081c995dd85c99081c1bdbdb608a1b604482015290519081900360640190fd5b6001600160a01b038216600090815260046020526040902054610315908263ffffffff61064716565b6001600160a01b03808416600090815260046020526040902091825542600192830155905461034d911633308463ffffffff6106a816565b5050565b6001546001600160a01b031681565b6003546001600160a01b031681565b610377610504565b6103b6576040805162461bcd60e51b81526020600482018190526024820152600080516020610c92833981519152604482015290519081900360640190fd5b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b6002546001600160a01b03821660009081526004602052604090206001015401919050565b61042d610504565b61046c576040805162461bcd60e51b81526020600482018190526024820152600080516020610c92833981519152604482015290519081900360640190fd5b6001600160a01b0382161580159061048c57506001600160a01b03811615155b6104c75760405162461bcd60e51b8152600401808060200182810382526030815260200180610cdc6030913960400191505060405180910390fd5b600380546001600160a01b039384166001600160a01b03199182161790915560018054929093169116179055565b6000546001600160a01b031690565b600080546001600160a01b0316610519610708565b6001600160a01b031614905090565b6001600160a01b031660009081526004602052604090205490565b61054d338261070c565b50565b610558610504565b610597576040805162461bcd60e51b81526020600482018190526024820152600080516020610c92833981519152604482015290519081900360640190fd5b61054d816108a7565b6003546001600160a01b031633146105f1576040805162461bcd60e51b815260206004820152600f60248201526e139bdd081c995dd85c99081c1bdbdb608a1b604482015290519081900360640190fd5b61034d828261070c565b610603610504565b610642576040805162461bcd60e51b81526020600482018190526024820152600080516020610c92833981519152604482015290519081900360640190fd5b600255565b6000828201838110156106a1576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052610702908590610947565b50505050565b3390565b6001600160a01b0382166000908152600460205260409020541580159061074d57506001600160a01b03821660009081526004602052604090206001015415155b61078d576040805162461bcd60e51b815260206004820152600c60248201526b6e6f74206170706c6965642160a01b604482015290519081900360640190fd5b61079682610400565b4210156107ea576040805162461bcd60e51b815260206004820152601960248201527f49742773206e6f742074696d6520746f20776974686472617700000000000000604482015290519081900360640190fd5b6001600160a01b03821660009081526004602052604090205481111561082557506001600160a01b0381166000908152600460205260409020545b6001600160a01b03821660009081526004602052604090205461084e908263ffffffff610aff16565b6001600160a01b038316600090815260046020526040902081905561088a576001600160a01b0382166000908152600460205260408120600101555b60015461034d906001600160a01b0316838363ffffffff610b4116565b6001600160a01b0381166108ec5760405162461bcd60e51b8152600401808060200182810382526026815260200180610c6c6026913960400191505060405180910390fd5b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b610959826001600160a01b0316610b98565b6109aa576040805162461bcd60e51b815260206004820152601f60248201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400604482015290519081900360640190fd5b60006060836001600160a01b0316836040518082805190602001908083835b602083106109e85780518252601f1990920191602091820191016109c9565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114610a4a576040519150601f19603f3d011682016040523d82523d6000602084013e610a4f565b606091505b509150915081610aa6576040805162461bcd60e51b815260206004820181905260248201527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604482015290519081900360640190fd5b80511561070257808060200190516020811015610ac257600080fd5b50516107025760405162461bcd60e51b815260040180806020018281038252602a815260200180610cb2602a913960400191505060405180910390fd5b60006106a183836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250610bd4565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052610b93908490610947565b505050565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4708115801590610bcc5750808214155b949350505050565b60008184841115610c635760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015610c28578181015183820152602001610c10565b50505050905090810190601f168015610c555780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50505090039056fe4f776e61626c653a206e6577206f776e657220697320746865207a65726f20616464726573734f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65725361666545524332303a204552433230206f7065726174696f6e20646964206e6f74207375636365656472657761726420706f6f6c20616e6420746f6b656e20616464726573732073686f756c646e277420626520656d707479a265627a7a7231582069b905dc4638d83dda996b41b32bede1c2d0a7807eea90d125d1a7277076235a64736f6c63430005100032
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.