Address Contract Partially Verified
Address
0x39E9fB78b543748950827BF4c606F58724b67a80
Balance
0 ETH
Nonce
1
Code Size
6506 bytes
Creator
0x804CC8D4...ABdf at tx 0x46855193...23d90b
Indexed Transactions
0
Contract Bytecode
6506 bytes
0x608060405234801561001057600080fd5b50600436106101215760003560e01c8063630b5ba1116100ad57806398969e821161007157806398969e82146102ea578063e2bbb15814610316578063e7f3fbde14610339578063f2fde38b14610341578063f7c618c11461036757610121565b8063630b5ba11461024e5780636dc8d3ee14610256578063824e4e84146102795780638da5cb5b1461028157806393f1a40b146102a557610121565b8063441a3e70116100f4578063441a3e70146101cf5780634e71e0c8146101f257806351eb05a6146101fa5780635312ea8e1461021757806355bb14f21461023457610121565b80631526fe271461012657806316114acd1461017357806331e244e51461019b57806333ba8882146101a3575b600080fd5b6101436004803603602081101561013c57600080fd5b503561036f565b604080516001600160a01b0390951685526020850193909352838301919091526060830152519081900360800190f35b6101996004803603602081101561018957600080fd5b50356001600160a01b03166103b3565b005b6101996104a2565b610199600480360360408110156101b957600080fd5b50803590602001356001600160a01b0316610522565b610199600480360360408110156101e557600080fd5b508035906020013561079e565b610199610908565b6101996004803603602081101561021057600080fd5b503561097b565b6101996004803603602081101561022d57600080fd5b5035610b6f565b61023c610c0b565b60408051918252519081900360200190f35b610199610c11565b6101996004803603604081101561026c57600080fd5b5080359060200135610c34565b61023c610cff565b610289610d05565b604080516001600160a01b039092168252519081900360200190f35b6102d1600480360360408110156102bb57600080fd5b50803590602001356001600160a01b0316610d14565b6040805192835260208301919091528051918290030190f35b61023c6004803603604081101561030057600080fd5b50803590602001356001600160a01b0316610d38565b6101996004803603604081101561032c57600080fd5b5080359060200135610f52565b61023c6110a9565b6101996004803603602081101561035757600080fd5b50356001600160a01b03166110af565b61028961111d565b6002818154811061037f57600080fd5b600091825260209091206004909102018054600182015460028301546003909301546001600160a01b039092169350919084565b6000546001600160a01b031633146103ff576040805162461bcd60e51b815260206004820152600a6024820152694f776e6572206f6e6c7960b01b604482015290519081900360640190fd5b61040881611141565b61041157600080fd5b61049f33826001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b15801561046257600080fd5b505afa158015610476573d6000803e3d6000fd5b505050506040513d602081101561048c57600080fd5b50516001600160a01b03841691906111c7565b50565b6000546001600160a01b031633146104ee576040805162461bcd60e51b815260206004820152600a6024820152694f776e6572206f6e6c7960b01b604482015290519081900360640190fd5b6203f48042016008556040517f6b1781b6a866642ab4b231507581f61da4ea07637e9b6cc148eeaf6925000a9e90600090a1565b6000546001600160a01b0316331461056e576040805162461bcd60e51b815260206004820152600a6024820152694f776e6572206f6e6c7960b01b604482015290519081900360640190fd5b6001600160a01b038116158015906105b857507f000000000000000000000000cb5f72d37685c3d5ad0bb5f982443bc8fcdf570e6001600160a01b0316816001600160a01b031614155b80156105c45750600854155b6105cd57600080fd5b6001600160a01b03811660009081526005602052604090205460ff1615610629576040805162461bcd60e51b815260206004820152600b60248201526a506f6f6c2065786973747360a81b604482015290519081900360640190fd5b600254601411610671576040805162461bcd60e51b815260206004820152600e60248201526d546f6f206d616e7920706f6f6c7360901b604482015290519081900360640190fd5b6001600160a01b0381166000908152600560205260409020805460ff1916600117905561069c610c11565b6004546106a9908361121e565b6004908155604080516080810182526001600160a01b03938416815260208101948552600654918101918252600060608201818152600280546001810182559252915193027f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace81018054949095166001600160a01b03199094169390931790935592517f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5acf82015591517f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ad0830155517f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ad190910155565b6000600283815481106107ad57fe5b60009182526020808320868452600382526040808520338652909252922080546004909202909201925083111561082b576040805162461bcd60e51b815260206004820152601760248201527f416d6f756e74206d6f7265207468616e207374616b6564000000000000000000604482015290519081900360640190fd5b6108348461097b565b600061086e826001015461086864e8d4a510006108628760030154876000015461127f90919063ffffffff16565b906112d8565b9061131a565b9050801561088057610880338261135c565b83156108aa578154610892908561131a565b825582546108aa906001600160a01b031633866111c7565b600383015482546108c59164e8d4a51000916108629161127f565b6001830155604080518581529051869133917ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b5689181900360200190a35050505050565b6001546001600160a01b0316331461091f57600080fd5b600180546001600160a01b03191690556000805460405133926001600160a01b03909216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b03191633179055565b60006002828154811061098a57fe5b9060005260206000209060040201905060007f000000000000000000000000cb5f72d37685c3d5ad0bb5f982443bc8fcdf570e6001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b158015610a0957600080fd5b505afa158015610a1d573d6000803e3d6000fd5b505050506040513d6020811015610a3357600080fd5b50516002830154909150811415610a4b57505061049f565b6000610a6e610a656007548461131a90919063ffffffff16565b6006549061121e565b600783905560068190558354604080516370a0823160e01b815230600482015290519293506000926001600160a01b03909216916370a0823191602480820192602092909190829003018186803b158015610ac857600080fd5b505afa158015610adc573d6000803e3d6000fd5b505050506040513d6020811015610af257600080fd5b5051905080610b0b57506002909201919091555061049f565b6000610b386004546108628760010154610b3289600201548861131a90919063ffffffff16565b9061127f565b9050610b5b610b50836108628464e8d4a5100061127f565b60038701549061121e565b600386015550506002909201919091555050565b600060028281548110610b7e57fe5b600091825260208083208584526003825260408085203380875293528420805485825560018201959095556004909302018054909450919291610bce916001600160a01b039190911690836111c7565b604080518281529051859133917fbb757047c2b5f3974fe26b7c10f732e7bce710b0952a71082702781e62ae05959181900360200190a350505050565b60025490565b60025460005b81811015610c3057610c288161097b565b600101610c17565b5050565b6000546001600160a01b03163314610c80576040805162461bcd60e51b815260206004820152600a6024820152694f776e6572206f6e6c7960b01b604482015290519081900360640190fd5b60085415610c8d57600080fd5b610c95610c11565b610cd281610ccc60028581548110610ca957fe5b90600052602060002090600402016001015460045461131a90919063ffffffff16565b9061121e565b6004819055508060028381548110610ce657fe5b9060005260206000209060040201600101819055505050565b60085481565b6000546001600160a01b031681565b60036020908152600092835260408084209091529082529020805460019091015482565b60008060028481548110610d4857fe5b60009182526020808320878452600380835260408086206001600160a01b03808b168852908552818720600496870290940192830154835483516370a0823160e01b8152309881019890985292519398509396939593949116926370a082319260248083019392829003018186803b158015610dc357600080fd5b505afa158015610dd7573d6000803e3d6000fd5b505050506040513d6020811015610ded57600080fd5b5051604080516370a0823160e01b815230600482015290519192506000916001600160a01b037f000000000000000000000000cb5f72d37685c3d5ad0bb5f982443bc8fcdf570e16916370a08231916024808301926020929190829003018186803b158015610e5b57600080fd5b505afa158015610e6f573d6000803e3d6000fd5b505050506040513d6020811015610e8557600080fd5b505160065460075491925090821115610eba57610eb7610eb06007548461131a90919063ffffffff16565b829061121e565b90505b856002015481118015610ecc57508215155b15610f1b576000610ef86004546108628960010154610b328b600201548761131a90919063ffffffff16565b9050610f17610f10856108628464e8d4a5100061127f565b869061121e565b9450505b610f43856001015461086864e8d4a51000610862888a6000015461127f90919063ffffffff16565b96505050505050505b92915050565b60085415610f97576040805162461bcd60e51b815260206004820152600d60248201526c5769746864726177206f6e6c7960981b604482015290519081900360640190fd5b600060028381548110610fa657fe5b60009182526020808320868452600382526040808520338652909252922060049091029091019150610fd78461097b565b80541561102057600061100c826001015461086864e8d4a510006108628760030154876000015461127f90919063ffffffff16565b9050801561101e5761101e338261135c565b505b821561104c57815461103d906001600160a01b03163330866114d7565b8054611049908461121e565b81555b600382015481546110679164e8d4a51000916108629161127f565b6001820155604080518481529051859133917f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a159181900360200190a350505050565b60045481565b6000546001600160a01b031633146110fb576040805162461bcd60e51b815260206004820152600a6024820152694f776e6572206f6e6c7960b01b604482015290519081900360640190fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055565b7f000000000000000000000000cb5f72d37685c3d5ad0bb5f982443bc8fcdf570e81565b6000600854600014158015611157575060085442115b15611164575060016111c2565b7f000000000000000000000000cb5f72d37685c3d5ad0bb5f982443bc8fcdf570e6001600160a01b0316826001600160a01b0316141580156111bf57506001600160a01b03821660009081526005602052604090205460ff16155b90505b919050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611219908490611537565b505050565b600082820183811015611278576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b60008261128e57506000610f4c565b8282028284828161129b57fe5b04146112785760405162461bcd60e51b81526004018080602001828103825260218152602001806118ea6021913960400191505060405180910390fd5b600061127883836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f0000000000008152506115e8565b600061127883836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f77000081525061168a565b60007f000000000000000000000000cb5f72d37685c3d5ad0bb5f982443bc8fcdf570e6001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b1580156113cb57600080fd5b505afa1580156113df573d6000803e3d6000fd5b505050506040513d60208110156113f557600080fd5b5051905061143d8382841161140a578361140c565b825b6001600160a01b037f000000000000000000000000cb5f72d37685c3d5ad0bb5f982443bc8fcdf570e1691906111c7565b604080516370a0823160e01b815230600482015290516001600160a01b037f000000000000000000000000cb5f72d37685c3d5ad0bb5f982443bc8fcdf570e16916370a08231916024808301926020929190829003018186803b1580156114a357600080fd5b505afa1580156114b7573d6000803e3d6000fd5b505050506040513d60208110156114cd57600080fd5b5051600755505050565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052611531908590611537565b50505050565b606061158c826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166116e49092919063ffffffff16565b805190915015611219578080602001905160208110156115ab57600080fd5b50516112195760405162461bcd60e51b815260040180806020018281038252602a81526020018061190b602a913960400191505060405180910390fd5b600081836116745760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015611639578181015183820152602001611621565b50505050905090810190601f1680156116665780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50600083858161168057fe5b0495945050505050565b600081848411156116dc5760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315611639578181015183820152602001611621565b505050900390565b60606116f384846000856116fb565b949350505050565b60608247101561173c5760405162461bcd60e51b81526004018080602001828103825260268152602001806118c46026913960400191505060405180910390fd5b61174585611857565b611796576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b60006060866001600160a01b031685876040518082805190602001908083835b602083106117d55780518252601f1990920191602091820191016117b6565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114611837576040519150601f19603f3d011682016040523d82523d6000602084013e61183c565b606091505b509150915061184c82828661185d565b979650505050505050565b3b151590565b6060831561186c575081611278565b82511561187c5782518084602001fd5b60405162461bcd60e51b815260206004820181815284516024840152845185939192839260440191908501908083836000831561163957818101518382015260200161162156fe416464726573733a20696e73756666696369656e742062616c616e636520666f722063616c6c536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f775361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564a26469706673582212201a25ded5bcecc463274326540a5f79f392569e5b58bd3d4e387da73e988e071b64736f6c63430007040033
Verified Source Code Partial Match
Compiler: v0.7.4+commit.3f05b770
EVM: istanbul
Optimization: Yes (200 runs)
Owned.sol 36 lines
// SPDX-License-Identifier: J-J-J-JENGA!!!
pragma solidity ^0.7.4;
/* ROOTKIT:
Provides ownerOnly() modifier
Allows for ownership transfer but requires the new
owner to claim (accept) ownership
Safer because no accidental transfers or renouncing
*/
import "./IOwned.sol";
abstract contract Owned is IOwned
{
address public override owner = msg.sender;
address internal pendingOwner;
modifier ownerOnly()
{
require (msg.sender == owner, "Owner only");
_;
}
function transferOwnership(address newOwner) public override ownerOnly()
{
pendingOwner = newOwner;
}
function claimOwnership() public override
{
require (pendingOwner == msg.sender);
pendingOwner = address(0);
emit OwnershipTransferred(owner, msg.sender);
owner = msg.sender;
}
}
IERC20.sol 19 lines
// SPDX-License-Identifier: J-J-J-JENGA!!!
pragma solidity ^0.7.4;
interface IERC20
{
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
function totalSupply() external view returns (uint256);
function balanceOf(address _account) external view returns (uint256);
function transfer(address _recipient, uint256 _amount) external returns (bool);
function allowance(address _owner, address _spender) external view returns (uint256);
function approve(address _spender, uint256 _amount) external returns (bool);
function transferFrom(address _sender, address _recipient, uint256 _amount) external returns (bool);
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
}
IOwned.sol 12 lines
// SPDX-License-Identifier: J-J-J-JENGA!!!
pragma solidity ^0.7.4;
interface IOwned
{
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
function owner() external view returns (address);
function transferOwnership(address newOwner) external;
function claimOwnership() external;
}
Address.sol 188 lines
// SPDX-License-Identifier: J-J-J-JENGA!!!
pragma solidity ^0.7.4;
/**
* @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;
// solhint-disable-next-line no-inline-assembly
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");
// solhint-disable-next-line avoid-low-level-calls, avoid-call-value
(bool success, ) = recipient.call{ value: amount }("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @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");
// solhint-disable-next-line avoid-low-level-calls
(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");
// solhint-disable-next-line avoid-low-level-calls
(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.3._
*/
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.3._
*/
function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = target.delegatecall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
if (success) {
return returndata;
} else {
// 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
// solhint-disable-next-line no-inline-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
SafeMath.sol 66 lines
// SPDX-License-Identifier: J-J-J-JENGA!!!
pragma solidity ^0.7.4;
/* ROOTKIT:
O wherefore art thou 8 point O
*/
library SafeMath
{
function add(uint256 a, uint256 b) internal pure returns (uint256)
{
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256)
{
return sub(a, b, "SafeMath: subtraction overflow");
}
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256)
{
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256)
{
// 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;
}
function div(uint256 a, uint256 b) internal pure returns (uint256)
{
return div(a, b, "SafeMath: division by zero");
}
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256)
{
require(b > 0, errorMessage);
uint256 c = a / b;
return c;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256)
{
return mod(a, b, "SafeMath: modulo by zero");
}
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256)
{
require(b != 0, errorMessage);
return a % b;
}
}
SafeERC20.sol 62 lines
// SPDX-License-Identifier: J-J-J-JENGA!!!
pragma solidity ^0.7.4;
/* ROOTKIT:
Modified to remove some junk
Also modified to remove silly restrictions (traps!) within safeApprove
*/
import "./IERC20.sol";
import "./SafeMath.sol";
import "./Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using SafeMath for uint256;
using Address for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @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 {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
/**
* @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
// solhint-disable-next-line max-line-length
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
RootKitStaking.sol 206 lines
// SPDX-License-Identifier: J-J-J-JENGA!!!
pragma solidity ^0.7.4;
/* ROOTKIT:
From https://raw.githubusercontent.com/sushiswap/sushiswap/master/contracts/MasterChef.sol
Except a million times better
*/
import "./Owned.sol";
import "./TokensRecoverable.sol";
import "./IERC20.sol";
import "./SafeMath.sol";
import "./SafeERC20.sol";
contract RootKitStaking is Owned, TokensRecoverable
{
using SafeMath for uint256;
using SafeERC20 for IERC20;
event Deposit(address indexed user, uint256 indexed poolId, uint256 amount);
event Withdraw(address indexed user, uint256 indexed poolId, uint256 amount);
event EmergencyWithdraw(address indexed user, uint256 indexed poolId, uint256 amount);
event Emergency();
struct UserInfo
{
uint256 amountStaked;
uint256 rewardDebt;
}
struct PoolInfo
{
IERC20 token;
uint256 allocationPoints;
uint256 lastTotalReward;
uint256 accRewardPerShare;
}
IERC20 public immutable rewardToken;
PoolInfo[] public poolInfo;
mapping (uint256 => mapping (address => UserInfo)) public userInfo;
uint256 public totalAllocationPoints;
mapping (IERC20 => bool) existingPools;
uint256 constant maxPoolCount = 20; // to simplify things and ensure massUpdatePools is safe
uint256 totalReward;
uint256 lastRewardBalance;
uint256 public emergencyRecoveryTimestamp;
constructor(IERC20 _rewardToken)
{
rewardToken = _rewardToken;
}
function poolInfoCount() external view returns (uint256)
{
return poolInfo.length;
}
function addPool(uint256 _allocationPoints, IERC20 _token) public ownerOnly()
{
require (address(_token) != address(0) && _token != rewardToken && emergencyRecoveryTimestamp == 0);
require (!existingPools[_token], "Pool exists");
require (poolInfo.length < maxPoolCount, "Too many pools");
existingPools[_token] = true;
massUpdatePools();
totalAllocationPoints = totalAllocationPoints.add(_allocationPoints);
poolInfo.push(PoolInfo({
token: _token,
allocationPoints: _allocationPoints,
lastTotalReward: totalReward,
accRewardPerShare: 0
}));
}
function setPoolAllocationPoints(uint256 _poolId, uint256 _allocationPoints) public ownerOnly()
{
require (emergencyRecoveryTimestamp == 0);
massUpdatePools();
totalAllocationPoints = totalAllocationPoints.sub(poolInfo[_poolId].allocationPoints).add(_allocationPoints);
poolInfo[_poolId].allocationPoints = _allocationPoints;
}
function pendingReward(uint256 _poolId, address _user) external view returns (uint256)
{
PoolInfo storage pool = poolInfo[_poolId];
UserInfo storage user = userInfo[_poolId][_user];
uint256 accRewardPerShare = pool.accRewardPerShare;
uint256 supply = pool.token.balanceOf(address(this));
uint256 balance = rewardToken.balanceOf(address(this));
uint256 _totalReward = totalReward;
if (balance > lastRewardBalance) {
_totalReward = _totalReward.add(balance.sub(lastRewardBalance));
}
if (_totalReward > pool.lastTotalReward && supply != 0) {
uint256 reward = _totalReward.sub(pool.lastTotalReward).mul(pool.allocationPoints).div(totalAllocationPoints);
accRewardPerShare = accRewardPerShare.add(reward.mul(1e12).div(supply));
}
return user.amountStaked.mul(accRewardPerShare).div(1e12).sub(user.rewardDebt);
}
function massUpdatePools() public
{
uint256 length = poolInfo.length;
for (uint256 poolId = 0; poolId < length; ++poolId) {
updatePool(poolId);
}
}
function updatePool(uint256 _poolId) public
{
PoolInfo storage pool = poolInfo[_poolId];
uint256 rewardBalance = rewardToken.balanceOf(address(this));
if (pool.lastTotalReward == rewardBalance) {
return;
}
uint256 _totalReward = totalReward.add(rewardBalance.sub(lastRewardBalance));
lastRewardBalance = rewardBalance;
totalReward = _totalReward;
uint256 supply = pool.token.balanceOf(address(this));
if (supply == 0) {
pool.lastTotalReward = _totalReward;
return;
}
uint256 reward = _totalReward.sub(pool.lastTotalReward).mul(pool.allocationPoints).div(totalAllocationPoints);
pool.accRewardPerShare = pool.accRewardPerShare.add(reward.mul(1e12).div(supply));
pool.lastTotalReward = _totalReward;
}
function deposit(uint256 _poolId, uint256 _amount) public
{
require (emergencyRecoveryTimestamp == 0, "Withdraw only");
PoolInfo storage pool = poolInfo[_poolId];
UserInfo storage user = userInfo[_poolId][msg.sender];
updatePool(_poolId);
if (user.amountStaked > 0) {
uint256 pending = user.amountStaked.mul(pool.accRewardPerShare).div(1e12).sub(user.rewardDebt);
if (pending > 0) {
safeRewardTransfer(msg.sender, pending);
}
}
if (_amount > 0) {
pool.token.safeTransferFrom(address(msg.sender), address(this), _amount);
user.amountStaked = user.amountStaked.add(_amount);
}
user.rewardDebt = user.amountStaked.mul(pool.accRewardPerShare).div(1e12);
emit Deposit(msg.sender, _poolId, _amount);
}
function withdraw(uint256 _poolId, uint256 _amount) public
{
PoolInfo storage pool = poolInfo[_poolId];
UserInfo storage user = userInfo[_poolId][msg.sender];
require(user.amountStaked >= _amount, "Amount more than staked");
updatePool(_poolId);
uint256 pending = user.amountStaked.mul(pool.accRewardPerShare).div(1e12).sub(user.rewardDebt);
if (pending > 0) {
safeRewardTransfer(msg.sender, pending);
}
if (_amount > 0) {
user.amountStaked = user.amountStaked.sub(_amount);
pool.token.safeTransfer(address(msg.sender), _amount);
}
user.rewardDebt = user.amountStaked.mul(pool.accRewardPerShare).div(1e12);
emit Withdraw(msg.sender, _poolId, _amount);
}
function emergencyWithdraw(uint256 _poolId) public
{
PoolInfo storage pool = poolInfo[_poolId];
UserInfo storage user = userInfo[_poolId][msg.sender];
uint256 amount = user.amountStaked;
user.amountStaked = 0;
user.rewardDebt = 0;
pool.token.safeTransfer(address(msg.sender), amount);
emit EmergencyWithdraw(msg.sender, _poolId, amount);
}
function safeRewardTransfer(address _to, uint256 _amount) internal
{
uint256 balance = rewardToken.balanceOf(address(this));
rewardToken.safeTransfer(_to, _amount > balance ? balance : _amount);
lastRewardBalance = rewardToken.balanceOf(address(this));
}
function declareEmergency() public ownerOnly()
{
// Funds will be recoverable 3 days after an emergency is declared
// By then, everyone should have withdrawn whatever they can
// Failing that (which is probably why there's an emergency) we can recover for them
emergencyRecoveryTimestamp = block.timestamp + 60*60*24*3;
emit Emergency();
}
function canRecoverTokens(IERC20 token) internal override view returns (bool)
{
if (emergencyRecoveryTimestamp != 0 && block.timestamp > emergencyRecoveryTimestamp) {
return true;
}
else {
return token != rewardToken && !existingPools[token];
}
}
}
TokensRecoverable.sol 28 lines
// SPDX-License-Identifier: J-J-J-JENGA!!!
pragma solidity ^0.7.4;
/* ROOTKIT:
Allows recovery of unexpected tokens (airdrops, etc)
Inheriters can customize logic by overriding canRecoverTokens
*/
import "./IERC20.sol";
import "./SafeERC20.sol";
import "./Owned.sol";
import "./ITokensRecoverable.sol";
abstract contract TokensRecoverable is Owned, ITokensRecoverable
{
using SafeERC20 for IERC20;
function recoverTokens(IERC20 token) public override ownerOnly()
{
require (canRecoverTokens(token));
token.safeTransfer(msg.sender, token.balanceOf(address(this)));
}
function canRecoverTokens(IERC20 token) internal virtual view returns (bool)
{
return address(token) != address(this);
}
}
ITokensRecoverable.sol 9 lines
// SPDX-License-Identifier: J-J-J-JENGA!!!
pragma solidity ^0.7.4;
import "./IERC20.sol";
interface ITokensRecoverable
{
function recoverTokens(IERC20 token) external;
}
Read Contract
emergencyRecoveryTimestamp 0x824e4e84 → uint256
owner 0x8da5cb5b → address
pendingReward 0x98969e82 → uint256
poolInfo 0x1526fe27 → address, uint256, uint256, uint256
poolInfoCount 0x55bb14f2 → uint256
rewardToken 0xf7c618c1 → address
totalAllocationPoints 0xe7f3fbde → uint256
userInfo 0x93f1a40b → uint256, uint256
Write Contract 11 functions
These functions modify contract state and require a wallet transaction to execute.
addPool 0x33ba8882
uint256 _allocationPoints
address _token
claimOwnership 0x4e71e0c8
No parameters
declareEmergency 0x31e244e5
No parameters
deposit 0xe2bbb158
uint256 _poolId
uint256 _amount
emergencyWithdraw 0x5312ea8e
uint256 _poolId
massUpdatePools 0x630b5ba1
No parameters
recoverTokens 0x16114acd
address token
setPoolAllocationPoints 0x6dc8d3ee
uint256 _poolId
uint256 _allocationPoints
transferOwnership 0xf2fde38b
address newOwner
updatePool 0x51eb05a6
uint256 _poolId
withdraw 0x441a3e70
uint256 _poolId
uint256 _amount
Recent Transactions
No transactions found for this address