More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 3,508 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Claim | 13269583 | 1026 days ago | IN | 0 ETH | 0.00417145 | ||||
Claim | 12931614 | 1078 days ago | IN | 0 ETH | 0.00175864 | ||||
Claim | 12882609 | 1086 days ago | IN | 0 ETH | 0.00117262 | ||||
Claim | 12846863 | 1092 days ago | IN | 0 ETH | 0.00101411 | ||||
Claim | 12831676 | 1094 days ago | IN | 0 ETH | 0.00313281 | ||||
Claim | 12816887 | 1096 days ago | IN | 0 ETH | 0.00242959 | ||||
Claim | 12801022 | 1099 days ago | IN | 0 ETH | 0.00180169 | ||||
Claim | 12790757 | 1100 days ago | IN | 0 ETH | 0.00251205 | ||||
Claim | 12790338 | 1101 days ago | IN | 0 ETH | 0.00150805 | ||||
Claim | 12789626 | 1101 days ago | IN | 0 ETH | 0.00216366 | ||||
Claim | 12785565 | 1101 days ago | IN | 0 ETH | 0.00278579 | ||||
Claim | 12782841 | 1102 days ago | IN | 0 ETH | 0.0022617 | ||||
Claim | 12782838 | 1102 days ago | IN | 0 ETH | 0.00226257 | ||||
Claim | 12782195 | 1102 days ago | IN | 0 ETH | 0.00243011 | ||||
Claim | 12763353 | 1105 days ago | IN | 0 ETH | 0.00082868 | ||||
Claim | 12763334 | 1105 days ago | IN | 0 ETH | 0.00041956 | ||||
Claim | 12763187 | 1105 days ago | IN | 0 ETH | 0.00020913 | ||||
0x30786131 | 12763176 | 1105 days ago | IN | 0 ETH | 0.00029313 | ||||
0x30786131 | 12763157 | 1105 days ago | IN | 0 ETH | 0.00029313 | ||||
0x30786131 | 12763149 | 1105 days ago | IN | 0 ETH | 0.00029313 | ||||
Claim | 12763121 | 1105 days ago | IN | 0 ETH | 0.00023901 | ||||
Claim | 12761967 | 1105 days ago | IN | 0 ETH | 0.00041863 | ||||
Claim | 12750781 | 1107 days ago | IN | 0 ETH | 0.00083703 | ||||
Claim | 12739563 | 1108 days ago | IN | 0 ETH | 0.00142444 | ||||
Claim | 12739020 | 1109 days ago | IN | 0 ETH | 0.00209397 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
MerkleDistributor
Compiler Version
v0.6.12+commit.27d51765
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2021-03-25 */ // SPDX-License-Identifier: AGPL-3.0-only pragma solidity ^0.6.0; pragma experimental ABIEncoderV2; // File: @openzeppelin/contracts/token/ERC20/IERC20.sol /** * @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); } // File: @openzeppelin/contracts/math/SafeMath.sol /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } } // File: @openzeppelin/contracts/utils/Address.sol pragma solidity ^0.6.2; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // According to EIP-1052, 0x0 is the value returned for not-yet created accounts // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned // for accounts without code, i.e. `keccak256('')` bytes32 codehash; bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; // solhint-disable-next-line no-inline-assembly assembly { codehash := extcodehash(account) } return (codehash != accountHash && codehash != 0x0); } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{ value: amount }(""); require(success, "Address: unable to send value, recipient may have reverted"); } } // File: @openzeppelin/contracts/token/ERC20/SafeERC20.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 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/cryptography/MerkleProof.sol /** * @dev These functions deal with verification of Merkle trees (hash trees), */ library MerkleProof { /** * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree * defined by `root`. For this, a `proof` must be provided, containing * sibling hashes on the branch from the leaf to the root of the tree. Each * pair of leaves and each pair of pre-images are assumed to be sorted. */ function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) { bytes32 computedHash = leaf; for (uint256 i = 0; i < proof.length; i++) { bytes32 proofElement = proof[i]; if (computedHash <= proofElement) { // Hash(current computed hash + current element of the proof) computedHash = keccak256(abi.encodePacked(computedHash, proofElement)); } else { // Hash(current element of the proof + current computed hash) computedHash = keccak256(abi.encodePacked(proofElement, computedHash)); } } // Check if the computed hash (root) is equal to the provided root return computedHash == root; } } // File: @openzeppelin/contracts/GSN/Context.sol /* * @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 { } function _msgSender() internal view virtual returns (address payable) { return msg.sender; } function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } } // File: @openzeppelin/contracts/access/Ownable.sol /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor () internal { address msgSender = _msgSender(); _owner = msgSender; emit OwnershipTransferred(address(0), msgSender); } /** * @dev Returns the address of the current owner. */ function owner() public view returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(_owner == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } } // File: contracts/merkle-distributor/implementation/MerkleDistributor.sol /** * Inspired by: * - https://github.com/pie-dao/vested-token-migration-app * - https://github.com/Uniswap/merkle-distributor * - https://github.com/balancer-labs/erc20-redeemable * * @title MerkleDistributor contract. * @notice Allows an owner to distribute any reward ERC20 to claimants according to Merkle roots. The owner can specify * multiple Merkle roots distributions with customized reward currencies. * @dev The Merkle trees are not validated in any way, so the system assumes the contract owner behaves honestly. */ contract MerkleDistributor is Ownable { using SafeMath for uint256; using SafeERC20 for IERC20; // A Window maps a Merkle root to a reward token address. struct Window { // Merkle root describing the distribution. bytes32 merkleRoot; // Currency in which reward is processed. IERC20 rewardToken; // IPFS hash of the merkle tree. Can be used to independently fetch recipient proofs and tree. Note that the canonical // data type for storing an IPFS hash is a multihash which is the concatenation of <varint hash function code> // <varint digest size in bytes><hash function output>. We opted to store this in a string type to make it easier // for users to query the ipfs data without needing to reconstruct the multihash. to view the IPFS data simply // go to https://cloudflare-ipfs.com/ipfs/<IPFS-HASH>. string ipfsHash; } // Represents an account's claim for `amount` within the Merkle root located at the `windowIndex`. struct Claim { uint256 windowIndex; uint256 amount; uint256 accountIndex; // Used only for bitmap. Assumed to be unique for each claim. address account; bytes32[] merkleProof; } // Windows are mapped to arbitrary indices. mapping(uint256 => Window) public merkleWindows; // Index of next created Merkle root. uint256 public nextCreatedIndex; // Track which accounts have claimed for each window index. // Note: uses a packed array of bools for gas optimization on tracking certain claims. Copied from Uniswap's contract. mapping(uint256 => mapping(uint256 => uint256)) private claimedBitMap; /**************************************** * EVENTS ****************************************/ event Claimed( address indexed caller, uint256 windowIndex, address indexed account, uint256 accountIndex, uint256 amount, address indexed rewardToken ); event CreatedWindow( uint256 indexed windowIndex, uint256 rewardsDeposited, address indexed rewardToken, address owner ); event WithdrawRewards(address indexed owner, uint256 amount, address indexed currency); event DeleteWindow(uint256 indexed windowIndex, address owner); /**************************** * ADMIN FUNCTIONS ****************************/ /** * @notice Set merkle root for the next available window index and seed allocations. * @notice Callable only by owner of this contract. Caller must have approved this contract to transfer * `rewardsToDeposit` amount of `rewardToken` or this call will fail. Importantly, we assume that the * owner of this contract correctly chooses an amount `rewardsToDeposit` that is sufficient to cover all * claims within the `merkleRoot`. Otherwise, a race condition can be created. This situation can occur * because we do not segregate reward balances by window, for code simplicity purposes. * (If `rewardsToDeposit` is purposefully insufficient to payout all claims, then the admin must * subsequently transfer in rewards or the following situation can occur). * Example race situation: * - Window 1 Tree: Owner sets `rewardsToDeposit=100` and insert proofs that give claimant A 50 tokens and * claimant B 51 tokens. The owner has made an error by not setting the `rewardsToDeposit` correctly to 101. * - Window 2 Tree: Owner sets `rewardsToDeposit=1` and insert proofs that give claimant A 1 token. The owner * correctly set `rewardsToDeposit` this time. * - At this point contract owns 100 + 1 = 101 tokens. Now, imagine the following sequence: * (1) Claimant A claims 50 tokens for Window 1, contract now has 101 - 50 = 51 tokens. * (2) Claimant B claims 51 tokens for Window 1, contract now has 51 - 51 = 0 tokens. * (3) Claimant A tries to claim 1 token for Window 2 but fails because contract has 0 tokens. * - In summary, the contract owner created a race for step(2) and step(3) in which the first claim would * succeed and the second claim would fail, even though both claimants would expect their claims to succeed. * @param rewardsToDeposit amount of rewards to deposit to seed this allocation. * @param rewardToken ERC20 reward token. * @param merkleRoot merkle root describing allocation. * @param ipfsHash hash of IPFS object, conveniently stored for clients */ function setWindow( uint256 rewardsToDeposit, address rewardToken, bytes32 merkleRoot, string memory ipfsHash ) external onlyOwner { uint256 indexToSet = nextCreatedIndex; nextCreatedIndex = indexToSet.add(1); _setWindow(indexToSet, rewardsToDeposit, rewardToken, merkleRoot, ipfsHash); } /** * @notice Delete merkle root at window index. * @dev Callable only by owner. Likely to be followed by a withdrawRewards call to clear contract state. * @param windowIndex merkle root index to delete. */ function deleteWindow(uint256 windowIndex) external onlyOwner { delete merkleWindows[windowIndex]; emit DeleteWindow(windowIndex, msg.sender); } /** * @notice Emergency method that transfers rewards out of the contract if the contract was configured improperly. * @dev Callable only by owner. * @param rewardCurrency rewards to withdraw from contract. * @param amount amount of rewards to withdraw. */ function withdrawRewards(address rewardCurrency, uint256 amount) external onlyOwner { IERC20(rewardCurrency).safeTransfer(msg.sender, amount); emit WithdrawRewards(msg.sender, amount, rewardCurrency); } /**************************** * NON-ADMIN FUNCTIONS ****************************/ /** * @notice Batch claims to reduce gas versus individual submitting all claims. Method will fail * if any individual claims within the batch would fail. * @dev Optimistically tries to batch together consecutive claims for the same account and same * reward token to reduce gas. Therefore, the most gas-cost-optimal way to use this method * is to pass in an array of claims sorted by account and reward currency. * @param claims array of claims to claim. */ function claimMulti(Claim[] memory claims) external { uint256 batchedAmount = 0; uint256 claimCount = claims.length; for (uint256 i = 0; i < claimCount; i++) { Claim memory _claim = claims[i]; _verifyAndMarkClaimed(_claim); batchedAmount = batchedAmount.add(_claim.amount); // If the next claim is NOT the same account or the same token (or this claim is the last one), // then disburse the `batchedAmount` to the current claim's account for the current claim's reward token. uint256 nextI = i + 1; address currentRewardToken = address(merkleWindows[_claim.windowIndex].rewardToken); if ( nextI == claimCount || // This claim is last claim. claims[nextI].account != _claim.account || // Next claim account is different than current one. address(merkleWindows[claims[nextI].windowIndex].rewardToken) != currentRewardToken // Next claim reward token is different than current one. ) { IERC20(currentRewardToken).safeTransfer(_claim.account, batchedAmount); batchedAmount = 0; } } } /** * @notice Claim amount of reward tokens for account, as described by Claim input object. * @dev If the `_claim`'s `amount`, `accountIndex`, and `account` do not exactly match the * values stored in the merkle root for the `_claim`'s `windowIndex` this method * will revert. * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof. */ function claim(Claim memory _claim) public { _verifyAndMarkClaimed(_claim); merkleWindows[_claim.windowIndex].rewardToken.safeTransfer(_claim.account, _claim.amount); } /** * @notice Returns True if the claim for `accountIndex` has already been completed for the Merkle root at * `windowIndex`. * @dev This method will only work as intended if all `accountIndex`'s are unique for a given `windowIndex`. * The onus is on the Owner of this contract to submit only valid Merkle roots. * @param windowIndex merkle root to check. * @param accountIndex account index to check within window index. * @return True if claim has been executed already, False otherwise. */ function isClaimed(uint256 windowIndex, uint256 accountIndex) public view returns (bool) { uint256 claimedWordIndex = accountIndex / 256; uint256 claimedBitIndex = accountIndex % 256; uint256 claimedWord = claimedBitMap[windowIndex][claimedWordIndex]; uint256 mask = (1 << claimedBitIndex); return claimedWord & mask == mask; } /** * @notice Returns True if leaf described by {account, amount, accountIndex} is stored in Merkle root at given * window index. * @param _claim claim object describing amount, accountIndex, account, window index, and merkle proof. * @return valid True if leaf exists. */ function verifyClaim(Claim memory _claim) public view returns (bool valid) { bytes32 leaf = keccak256(abi.encodePacked(_claim.account, _claim.amount, _claim.accountIndex)); return MerkleProof.verify(_claim.merkleProof, merkleWindows[_claim.windowIndex].merkleRoot, leaf); } /**************************** * PRIVATE FUNCTIONS ****************************/ // Mark claim as completed for `accountIndex` for Merkle root at `windowIndex`. function _setClaimed(uint256 windowIndex, uint256 accountIndex) private { uint256 claimedWordIndex = accountIndex / 256; uint256 claimedBitIndex = accountIndex % 256; claimedBitMap[windowIndex][claimedWordIndex] = claimedBitMap[windowIndex][claimedWordIndex] | (1 << claimedBitIndex); } // Store new Merkle root at `windowindex`. Pull `rewardsDeposited` from caller to seed distribution for this root. function _setWindow( uint256 windowIndex, uint256 rewardsDeposited, address rewardToken, bytes32 merkleRoot, string memory ipfsHash ) private { Window storage window = merkleWindows[windowIndex]; window.merkleRoot = merkleRoot; window.rewardToken = IERC20(rewardToken); window.ipfsHash = ipfsHash; emit CreatedWindow(windowIndex, rewardsDeposited, rewardToken, msg.sender); window.rewardToken.safeTransferFrom(msg.sender, address(this), rewardsDeposited); } // Verify claim is valid and mark it as completed in this contract. function _verifyAndMarkClaimed(Claim memory _claim) private { // Check claimed proof against merkle window at given index. require(verifyClaim(_claim), "Incorrect merkle proof"); // Check the account has not yet claimed for this window. require(!isClaimed(_claim.windowIndex, _claim.accountIndex), "Account has already claimed for this window"); // Proof is correct and claim has not occurred yet, mark claimed complete. _setClaimed(_claim.windowIndex, _claim.accountIndex); emit Claimed( msg.sender, _claim.windowIndex, _claim.account, _claim.accountIndex, _claim.amount, address(merkleWindows[_claim.windowIndex].rewardToken) ); } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"uint256","name":"windowIndex","type":"uint256"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"accountIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"rewardToken","type":"address"}],"name":"Claimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"windowIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rewardsDeposited","type":"uint256"},{"indexed":true,"internalType":"address","name":"rewardToken","type":"address"},{"indexed":false,"internalType":"address","name":"owner","type":"address"}],"name":"CreatedWindow","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"windowIndex","type":"uint256"},{"indexed":false,"internalType":"address","name":"owner","type":"address"}],"name":"DeleteWindow","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":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"currency","type":"address"}],"name":"WithdrawRewards","type":"event"},{"inputs":[{"components":[{"internalType":"uint256","name":"windowIndex","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"accountIndex","type":"uint256"},{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32[]","name":"merkleProof","type":"bytes32[]"}],"internalType":"struct MerkleDistributor.Claim","name":"_claim","type":"tuple"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"windowIndex","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"accountIndex","type":"uint256"},{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32[]","name":"merkleProof","type":"bytes32[]"}],"internalType":"struct MerkleDistributor.Claim[]","name":"claims","type":"tuple[]"}],"name":"claimMulti","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"windowIndex","type":"uint256"}],"name":"deleteWindow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"windowIndex","type":"uint256"},{"internalType":"uint256","name":"accountIndex","type":"uint256"}],"name":"isClaimed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"merkleWindows","outputs":[{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"},{"internalType":"contract IERC20","name":"rewardToken","type":"address"},{"internalType":"string","name":"ipfsHash","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextCreatedIndex","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":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"rewardsToDeposit","type":"uint256"},{"internalType":"address","name":"rewardToken","type":"address"},{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"},{"internalType":"string","name":"ipfsHash","type":"string"}],"name":"setWindow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"windowIndex","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"accountIndex","type":"uint256"},{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32[]","name":"merkleProof","type":"bytes32[]"}],"internalType":"struct MerkleDistributor.Claim","name":"_claim","type":"tuple"}],"name":"verifyClaim","outputs":[{"internalType":"bool","name":"valid","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"rewardCurrency","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawRewards","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b50600061001b61006a565b600080546001600160a01b0319166001600160a01b0383169081178255604051929350917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a35061006e565b3390565b6113468061007d6000396000f3fe608060405234801561001057600080fd5b50600436106100b45760003560e01c8063a198496c11610071578063a198496c14610149578063d45118681461015c578063d6ef7af01461016f578063e2e441a314610182578063f2fde38b14610197578063f364c90c146101aa576100b4565b80634f512151146100b95780636be65179146100e2578063715018a6146100f7578063891b0d71146100ff5780638da5cb5b146101215780639f5a967214610136575b600080fd5b6100cc6100c7366004610e5b565b6101bd565b6040516100d9919061101b565b60405180910390f35b6100f56100f0366004610db2565b610223565b005b6100f5610349565b61011261010d366004610e8e565b6103d1565b6040516100d993929190611026565b610129610484565b6040516100d99190610fca565b6100f5610144366004610e8e565b610493565b6100f5610157366004610e5b565b610537565b6100f561016a366004610ea6565b610578565b6100f561017d366004610d88565b6105d2565b61018a61066a565b6040516100d99190611252565b6100f56101a5366004610d6d565b610670565b6100cc6101b8366004610f55565b610726565b6000808260600151836020015184604001516040516020016101e193929190610f76565b60408051601f1981840301815291815281516020928301206080860151865160009081526001909452919092205491925061021c9183610756565b9392505050565b8051600090815b818110156103435761023a610b71565b84828151811061024657fe5b60200260200101519050610259816107f3565b60208101516102699085906108cd565b815160009081526001602081905260409091208101549195508301906001600160a01b0316848214806102c9575082606001516001600160a01b03168783815181106102b157fe5b6020026020010151606001516001600160a01b031614155b806103145750806001600160a01b0316600160008985815181106102e957fe5b602090810291909101810151518252810191909152604001600020600101546001600160a01b031614155b15610338576060830151610333906001600160a01b03831690886108f2565b600095505b50505060010161022a565b50505050565b61035161094d565b6000546001600160a01b039081169116146103875760405162461bcd60e51b815260040161037e90611151565b60405180910390fd5b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b6001602081815260009283526040928390208054818401546002808401805488516101009882161598909802600019011691909104601f810186900486028701860190975286865291956001600160a01b0390911694929383018282801561047a5780601f1061044f5761010080835404028352916020019161047a565b820191906000526020600020905b81548152906001019060200180831161045d57829003601f168201915b5050505050905083565b6000546001600160a01b031690565b61049b61094d565b6000546001600160a01b039081169116146104c85760405162461bcd60e51b815260040161037e90611151565b6000818152600160208190526040822082815590810180546001600160a01b0319169055906104fa6002830182610ba9565b5050807f8fea52000ecb40f2262c672496dfadccc9d6290439bac487e084de8c57682d663360405161052c9190610fca565b60405180910390a250565b610540816107f3565b6060810151602080830151835160009081526001928390526040902090910154610575926001600160a01b03909116916108f2565b50565b61058061094d565b6000546001600160a01b039081169116146105ad5760405162461bcd60e51b815260040161037e90611151565b6002546105bb8160016108cd565b6002556105cb8186868686610951565b5050505050565b6105da61094d565b6000546001600160a01b039081169116146106075760405162461bcd60e51b815260040161037e90611151565b61061b6001600160a01b03831633836108f2565b816001600160a01b0316336001600160a01b03167ffb0872526787ac1be379aa37eaa9913b47d6d50c3f5fe5ec67ffe4282493670e8360405161065e9190611252565b60405180910390a35050565b60025481565b61067861094d565b6000546001600160a01b039081169116146106a55760405162461bcd60e51b815260040161037e90611151565b6001600160a01b0381166106cb5760405162461bcd60e51b815260040161037e9061106f565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b600082815260036020908152604080832061010085048452909152902054600160ff83161b908116145b92915050565b600081815b85518110156107e857600086828151811061077257fe5b602002602001015190508083116107b3578281604051602001610796929190610fa0565b6040516020818303038152906040528051906020012092506107df565b80836040516020016107c6929190610fa0565b6040516020818303038152906040528051906020012092505b5060010161075b565b509092149392505050565b6107fc816101bd565b6108185760405162461bcd60e51b815260040161037e906110b5565b61082a81600001518260400151610726565b156108475760405162461bcd60e51b815260040161037e90611186565b610859816000015182604001516109fd565b80516000908152600160208181526040928390209091015460608401518451848601519386015194516001600160a01b0393841695929093169333937f18bdb6adb84039f917775d1fb8e7b7e7737ad5915d12eef0e4654b85e18d07b4936108c2939291611272565b60405180910390a450565b60008282018381101561021c5760405162461bcd60e51b815260040161037e906110e5565b6109488363a9059cbb60e01b8484604051602401610911929190611002565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152610a2f565b505050565b3390565b600085815260016020818152604090922084815590810180546001600160a01b0319166001600160a01b03871617905582519091610996916002840191850190610bed565b50836001600160a01b0316867f521fe5bce65ac6af752c1083ec77facc5b6c13f40693e96eeca3747726fee9ad87336040516109d392919061125b565b60405180910390a360018101546109f5906001600160a01b0316333088610b14565b505050505050565b6000918252600360209081526040808420610100840485529091529091208054600160ff9093169290921b9091179055565b610a41826001600160a01b0316610b35565b610a5d5760405162461bcd60e51b815260040161037e9061121b565b60006060836001600160a01b031683604051610a799190610fae565b6000604051808303816000865af19150503d8060008114610ab6576040519150601f19603f3d011682016040523d82523d6000602084013e610abb565b606091505b509150915081610add5760405162461bcd60e51b815260040161037e9061111c565b8051156103435780806020019051810190610af89190610e3b565b6103435760405162461bcd60e51b815260040161037e906111d1565b610343846323b872dd60e01b85858560405160240161091193929190610fde565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590610b6957508115155b949350505050565b6040518060a0016040528060008152602001600081526020016000815260200160006001600160a01b03168152602001606081525090565b50805460018160011615610100020316600290046000825580601f10610bcf5750610575565b601f0160209004906000526020600020908101906105759190610c6b565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10610c2e57805160ff1916838001178555610c5b565b82800160010185558215610c5b579182015b82811115610c5b578251825591602001919060010190610c40565b50610c67929150610c6b565b5090565b5b80821115610c675760008155600101610c6c565b80356001600160a01b038116811461075057600080fd5b600060a08284031215610ca8578081fd5b610cb260a0611288565b9050813581526020808301358183015260408301356040830152610cd98460608501610c80565b6060830152608083013567ffffffffffffffff811115610cf857600080fd5b8301601f81018513610d0957600080fd5b8035610d1c610d17826112af565b611288565b8181528381019083850185840285018601891015610d3957600080fd5b600094505b83851015610d5c578035835260019490940193918501918501610d3e565b506080860152509295945050505050565b600060208284031215610d7e578081fd5b61021c8383610c80565b60008060408385031215610d9a578081fd5b610da48484610c80565b946020939093013593505050565b60006020808385031215610dc4578182fd5b823567ffffffffffffffff811115610dda578283fd5b8301601f81018513610dea578283fd5b8035610df8610d17826112af565b81815283810190838501865b84811015610e2d57610e1b8a888435890101610c97565b84529286019290860190600101610e04565b509098975050505050505050565b600060208284031215610e4c578081fd5b8151801515811461021c578182fd5b600060208284031215610e6c578081fd5b813567ffffffffffffffff811115610e82578182fd5b610b6984828501610c97565b600060208284031215610e9f578081fd5b5035919050565b60008060008060808587031215610ebb578182fd5b84359350602080860135610ece816112fb565b935060408601359250606086013567ffffffffffffffff80821115610ef1578384fd5b818801915088601f830112610f04578384fd5b813581811115610f12578485fd5b610f24601f8201601f19168501611288565b91508082528984828501011115610f39578485fd5b8084840185840137810190920192909252939692955090935050565b60008060408385031215610f67578182fd5b50508035926020909101359150565b60609390931b6bffffffffffffffffffffffff191683526014830191909152603482015260540190565b918252602082015260400190565b60008251610fc08184602087016112cf565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b03929092168252602082015260400190565b901515815260200190565b600084825260018060a01b03841660208301526060604083015282518060608401526110598160808501602087016112cf565b601f01601f191691909101608001949350505050565b60208082526026908201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160408201526564647265737360d01b606082015260800190565b60208082526016908201527524b731b7b93932b1ba1036b2b935b63290383937b7b360511b604082015260600190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252818101527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604082015260600190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252602b908201527f4163636f756e742068617320616c726561647920636c61696d656420666f722060408201526a746869732077696e646f7760a81b606082015260800190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b6020808252601f908201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400604082015260600190565b90815260200190565b9182526001600160a01b0316602082015260400190565b9283526020830191909152604082015260600190565b60405181810167ffffffffffffffff811182821017156112a757600080fd5b604052919050565b600067ffffffffffffffff8211156112c5578081fd5b5060209081020190565b60005b838110156112ea5781810151838201526020016112d2565b838111156103435750506000910152565b6001600160a01b038116811461057557600080fdfea2646970667358221220fe58190692178baf85e1671709fc6626f66d4db3a5ad895137661829006e178764736f6c634300060c0033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106100b45760003560e01c8063a198496c11610071578063a198496c14610149578063d45118681461015c578063d6ef7af01461016f578063e2e441a314610182578063f2fde38b14610197578063f364c90c146101aa576100b4565b80634f512151146100b95780636be65179146100e2578063715018a6146100f7578063891b0d71146100ff5780638da5cb5b146101215780639f5a967214610136575b600080fd5b6100cc6100c7366004610e5b565b6101bd565b6040516100d9919061101b565b60405180910390f35b6100f56100f0366004610db2565b610223565b005b6100f5610349565b61011261010d366004610e8e565b6103d1565b6040516100d993929190611026565b610129610484565b6040516100d99190610fca565b6100f5610144366004610e8e565b610493565b6100f5610157366004610e5b565b610537565b6100f561016a366004610ea6565b610578565b6100f561017d366004610d88565b6105d2565b61018a61066a565b6040516100d99190611252565b6100f56101a5366004610d6d565b610670565b6100cc6101b8366004610f55565b610726565b6000808260600151836020015184604001516040516020016101e193929190610f76565b60408051601f1981840301815291815281516020928301206080860151865160009081526001909452919092205491925061021c9183610756565b9392505050565b8051600090815b818110156103435761023a610b71565b84828151811061024657fe5b60200260200101519050610259816107f3565b60208101516102699085906108cd565b815160009081526001602081905260409091208101549195508301906001600160a01b0316848214806102c9575082606001516001600160a01b03168783815181106102b157fe5b6020026020010151606001516001600160a01b031614155b806103145750806001600160a01b0316600160008985815181106102e957fe5b602090810291909101810151518252810191909152604001600020600101546001600160a01b031614155b15610338576060830151610333906001600160a01b03831690886108f2565b600095505b50505060010161022a565b50505050565b61035161094d565b6000546001600160a01b039081169116146103875760405162461bcd60e51b815260040161037e90611151565b60405180910390fd5b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b6001602081815260009283526040928390208054818401546002808401805488516101009882161598909802600019011691909104601f810186900486028701860190975286865291956001600160a01b0390911694929383018282801561047a5780601f1061044f5761010080835404028352916020019161047a565b820191906000526020600020905b81548152906001019060200180831161045d57829003601f168201915b5050505050905083565b6000546001600160a01b031690565b61049b61094d565b6000546001600160a01b039081169116146104c85760405162461bcd60e51b815260040161037e90611151565b6000818152600160208190526040822082815590810180546001600160a01b0319169055906104fa6002830182610ba9565b5050807f8fea52000ecb40f2262c672496dfadccc9d6290439bac487e084de8c57682d663360405161052c9190610fca565b60405180910390a250565b610540816107f3565b6060810151602080830151835160009081526001928390526040902090910154610575926001600160a01b03909116916108f2565b50565b61058061094d565b6000546001600160a01b039081169116146105ad5760405162461bcd60e51b815260040161037e90611151565b6002546105bb8160016108cd565b6002556105cb8186868686610951565b5050505050565b6105da61094d565b6000546001600160a01b039081169116146106075760405162461bcd60e51b815260040161037e90611151565b61061b6001600160a01b03831633836108f2565b816001600160a01b0316336001600160a01b03167ffb0872526787ac1be379aa37eaa9913b47d6d50c3f5fe5ec67ffe4282493670e8360405161065e9190611252565b60405180910390a35050565b60025481565b61067861094d565b6000546001600160a01b039081169116146106a55760405162461bcd60e51b815260040161037e90611151565b6001600160a01b0381166106cb5760405162461bcd60e51b815260040161037e9061106f565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b600082815260036020908152604080832061010085048452909152902054600160ff83161b908116145b92915050565b600081815b85518110156107e857600086828151811061077257fe5b602002602001015190508083116107b3578281604051602001610796929190610fa0565b6040516020818303038152906040528051906020012092506107df565b80836040516020016107c6929190610fa0565b6040516020818303038152906040528051906020012092505b5060010161075b565b509092149392505050565b6107fc816101bd565b6108185760405162461bcd60e51b815260040161037e906110b5565b61082a81600001518260400151610726565b156108475760405162461bcd60e51b815260040161037e90611186565b610859816000015182604001516109fd565b80516000908152600160208181526040928390209091015460608401518451848601519386015194516001600160a01b0393841695929093169333937f18bdb6adb84039f917775d1fb8e7b7e7737ad5915d12eef0e4654b85e18d07b4936108c2939291611272565b60405180910390a450565b60008282018381101561021c5760405162461bcd60e51b815260040161037e906110e5565b6109488363a9059cbb60e01b8484604051602401610911929190611002565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152610a2f565b505050565b3390565b600085815260016020818152604090922084815590810180546001600160a01b0319166001600160a01b03871617905582519091610996916002840191850190610bed565b50836001600160a01b0316867f521fe5bce65ac6af752c1083ec77facc5b6c13f40693e96eeca3747726fee9ad87336040516109d392919061125b565b60405180910390a360018101546109f5906001600160a01b0316333088610b14565b505050505050565b6000918252600360209081526040808420610100840485529091529091208054600160ff9093169290921b9091179055565b610a41826001600160a01b0316610b35565b610a5d5760405162461bcd60e51b815260040161037e9061121b565b60006060836001600160a01b031683604051610a799190610fae565b6000604051808303816000865af19150503d8060008114610ab6576040519150601f19603f3d011682016040523d82523d6000602084013e610abb565b606091505b509150915081610add5760405162461bcd60e51b815260040161037e9061111c565b8051156103435780806020019051810190610af89190610e3b565b6103435760405162461bcd60e51b815260040161037e906111d1565b610343846323b872dd60e01b85858560405160240161091193929190610fde565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590610b6957508115155b949350505050565b6040518060a0016040528060008152602001600081526020016000815260200160006001600160a01b03168152602001606081525090565b50805460018160011615610100020316600290046000825580601f10610bcf5750610575565b601f0160209004906000526020600020908101906105759190610c6b565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10610c2e57805160ff1916838001178555610c5b565b82800160010185558215610c5b579182015b82811115610c5b578251825591602001919060010190610c40565b50610c67929150610c6b565b5090565b5b80821115610c675760008155600101610c6c565b80356001600160a01b038116811461075057600080fd5b600060a08284031215610ca8578081fd5b610cb260a0611288565b9050813581526020808301358183015260408301356040830152610cd98460608501610c80565b6060830152608083013567ffffffffffffffff811115610cf857600080fd5b8301601f81018513610d0957600080fd5b8035610d1c610d17826112af565b611288565b8181528381019083850185840285018601891015610d3957600080fd5b600094505b83851015610d5c578035835260019490940193918501918501610d3e565b506080860152509295945050505050565b600060208284031215610d7e578081fd5b61021c8383610c80565b60008060408385031215610d9a578081fd5b610da48484610c80565b946020939093013593505050565b60006020808385031215610dc4578182fd5b823567ffffffffffffffff811115610dda578283fd5b8301601f81018513610dea578283fd5b8035610df8610d17826112af565b81815283810190838501865b84811015610e2d57610e1b8a888435890101610c97565b84529286019290860190600101610e04565b509098975050505050505050565b600060208284031215610e4c578081fd5b8151801515811461021c578182fd5b600060208284031215610e6c578081fd5b813567ffffffffffffffff811115610e82578182fd5b610b6984828501610c97565b600060208284031215610e9f578081fd5b5035919050565b60008060008060808587031215610ebb578182fd5b84359350602080860135610ece816112fb565b935060408601359250606086013567ffffffffffffffff80821115610ef1578384fd5b818801915088601f830112610f04578384fd5b813581811115610f12578485fd5b610f24601f8201601f19168501611288565b91508082528984828501011115610f39578485fd5b8084840185840137810190920192909252939692955090935050565b60008060408385031215610f67578182fd5b50508035926020909101359150565b60609390931b6bffffffffffffffffffffffff191683526014830191909152603482015260540190565b918252602082015260400190565b60008251610fc08184602087016112cf565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b03929092168252602082015260400190565b901515815260200190565b600084825260018060a01b03841660208301526060604083015282518060608401526110598160808501602087016112cf565b601f01601f191691909101608001949350505050565b60208082526026908201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160408201526564647265737360d01b606082015260800190565b60208082526016908201527524b731b7b93932b1ba1036b2b935b63290383937b7b360511b604082015260600190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252818101527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604082015260600190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252602b908201527f4163636f756e742068617320616c726561647920636c61696d656420666f722060408201526a746869732077696e646f7760a81b606082015260800190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b6020808252601f908201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400604082015260600190565b90815260200190565b9182526001600160a01b0316602082015260400190565b9283526020830191909152604082015260600190565b60405181810167ffffffffffffffff811182821017156112a757600080fd5b604052919050565b600067ffffffffffffffff8211156112c5578081fd5b5060209081020190565b60005b838110156112ea5781810151838201526020016112d2565b838111156103435750506000910152565b6001600160a01b038116811461057557600080fdfea2646970667358221220fe58190692178baf85e1671709fc6626f66d4db3a5ad895137661829006e178764736f6c634300060c0033
Deployed Bytecode Sourcemap
20098:12340:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30031:296;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;26826:1288;;;;;;:::i;:::-;;:::i;:::-;;18903:148;;;:::i;21436:47::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;;:::i;18261:79::-;;;:::i;:::-;;;;;;;:::i;25489:167::-;;;;;;:::i;:::-;;:::i;28566:191::-;;;;;;:::i;:::-;;:::i;24882:363::-;;;;;;:::i;:::-;;:::i;25956:225::-;;;;;;:::i;:::-;;:::i;21535:31::-;;;:::i;:::-;;;;;;;:::i;19206:244::-;;;;;;:::i;:::-;;:::i;29330:377::-;;;;;;:::i;:::-;;:::i;30031:296::-;30094:10;30117:12;30159:6;:14;;;30175:6;:13;;;30190:6;:19;;;30142:68;;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;30142:68:0;;;;;;;;;30132:79;;30142:68;30132:79;;;;30248:18;;;;30282;;30268:33;;;;:13;:33;;;;;;;:44;30132:79;;-1:-1:-1;30229:90:0;;30132:79;30229:18;:90::i;:::-;30222:97;30031:296;-1:-1:-1;;;30031:296:0:o;26826:1288::-;26946:13;;26889:21;;;26970:1137;26994:10;26990:1;:14;26970:1137;;;27026:19;;:::i;:::-;27048:6;27055:1;27048:9;;;;;;;;;;;;;;27026:31;;27072:29;27094:6;27072:21;:29::i;:::-;27150:13;;;;27132:32;;:13;;:17;:32::i;:::-;27496:18;;27409:13;27482:33;;;27429:1;27482:33;;;;;;;;:45;;;27116:48;;-1:-1:-1;27425:5:0;;;-1:-1:-1;;;;;27482:45:0;27565:19;;;;:125;;;27676:6;:14;;;-1:-1:-1;;;;;27651:39:0;:6;27658:5;27651:13;;;;;;;;;;;;;;:21;;;-1:-1:-1;;;;;27651:39:0;;;27565:125;:299;;;;27846:18;-1:-1:-1;;;;;27781:83:0;27789:13;:40;27803:6;27810:5;27803:13;;;;;;;;;;;;;;;;;;;:25;27789:40;;;;;;;;;;27803:25;27789:40;:52;;;-1:-1:-1;;;;;27789:52:0;27781:83;;27565:299;27543:553;;;28014:14;;;;27974:70;;-1:-1:-1;;;;;27974:39:0;;;28030:13;27974:39;:70::i;:::-;28079:1;28063:17;;27543:553;-1:-1:-1;;;27006:3:0;;26970:1137;;;;26826:1288;;;:::o;18903:148::-;18483:12;:10;:12::i;:::-;18473:6;;-1:-1:-1;;;;;18473:6:0;;;:22;;;18465:67;;;;-1:-1:-1;;;18465:67:0;;;;;;;:::i;:::-;;;;;;;;;19010:1:::1;18994:6:::0;;18973:40:::1;::::0;-1:-1:-1;;;;;18994:6:0;;::::1;::::0;18973:40:::1;::::0;19010:1;;18973:40:::1;19041:1;19024:19:::0;;-1:-1:-1;;;;;;19024:19:0::1;::::0;;18903:148::o;21436:47::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;21436:47:0;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;21436:47:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;18261:79::-;18299:7;18326:6;-1:-1:-1;;;;;18326:6:0;18261:79;:::o;25489:167::-;18483:12;:10;:12::i;:::-;18473:6;;-1:-1:-1;;;;;18473:6:0;;;:22;;;18465:67;;;;-1:-1:-1;;;18465:67:0;;;;;;;:::i;:::-;25569:26:::1;::::0;;;:13:::1;:26;::::0;;;;;;25562:33;;;;;::::1;::::0;;-1:-1:-1;;;;;;25562:33:0::1;::::0;;25569:26;25562:33:::1;;::::0;::::1;25569:26:::0;25562:33:::1;:::i;:::-;;;25624:11;25611:37;25637:10;25611:37;;;;;;:::i;:::-;;;;;;;;25489:167:::0;:::o;28566:191::-;28620:29;28642:6;28620:21;:29::i;:::-;28719:14;;;;28735:13;;;;;28674:18;;28660:33;;;;:13;:33;;;;;;;:45;;;;:89;;-1:-1:-1;;;;;28660:45:0;;;;:58;:89::i;:::-;28566:191;:::o;24882:363::-;18483:12;:10;:12::i;:::-;18473:6;;-1:-1:-1;;;;;18473:6:0;;;:22;;;18465:67;;;;-1:-1:-1;;;18465:67:0;;;;;;;:::i;:::-;25086:16:::1;::::0;25132:17:::1;25086:16:::0;25147:1:::1;25132:14;:17::i;:::-;25113:16;:36:::0;25162:75:::1;25173:10:::0;25185:16;25203:11;25216:10;25228:8;25162:10:::1;:75::i;:::-;18543:1;24882:363:::0;;;;:::o;25956:225::-;18483:12;:10;:12::i;:::-;18473:6;;-1:-1:-1;;;;;18473:6:0;;;:22;;;18465:67;;;;-1:-1:-1;;;18465:67:0;;;;;;;:::i;:::-;26051:55:::1;-1:-1:-1::0;;;;;26051:35:0;::::1;26087:10;26099:6:::0;26051:35:::1;:55::i;:::-;26158:14;-1:-1:-1::0;;;;;26122:51:0::1;26138:10;-1:-1:-1::0;;;;;26122:51:0::1;;26150:6;26122:51;;;;;;:::i;:::-;;;;;;;;25956:225:::0;;:::o;21535:31::-;;;;:::o;19206:244::-;18483:12;:10;:12::i;:::-;18473:6;;-1:-1:-1;;;;;18473:6:0;;;:22;;;18465:67;;;;-1:-1:-1;;;18465:67:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;19295:22:0;::::1;19287:73;;;;-1:-1:-1::0;;;19287:73:0::1;;;;;;;:::i;:::-;19397:6;::::0;;19376:38:::1;::::0;-1:-1:-1;;;;;19376:38:0;;::::1;::::0;19397:6;::::1;::::0;19376:38:::1;::::0;::::1;19425:6;:17:::0;;-1:-1:-1;;;;;;19425:17:0::1;-1:-1:-1::0;;;;;19425:17:0;;;::::1;::::0;;;::::1;::::0;;19206:244::o;29330:377::-;29413:4;29563:26;;;:13;:26;;;;;;;;29472:3;29457:18;;29563:44;;;;;;;;29634:1;29512:18;;;29634:20;29673:18;;;:26;29330:377;;;;;:::o;15260:796::-;15351:4;15391;15351;15408:525;15432:5;:12;15428:1;:16;15408:525;;;15466:20;15489:5;15495:1;15489:8;;;;;;;;;;;;;;15466:31;;15534:12;15518;:28;15514:408;;15688:12;15702;15671:44;;;;;;;;;:::i;:::-;;;;;;;;;;;;;15661:55;;;;;;15646:70;;15514:408;;;15878:12;15892;15861:44;;;;;;;;;:::i;:::-;;;;;;;;;;;;;15851:55;;;;;;15836:70;;15514:408;-1:-1:-1;15446:3:0;;15408:525;;;-1:-1:-1;16028:20:0;;;;15260:796;-1:-1:-1;;;15260:796:0:o;31646:789::-;31795:19;31807:6;31795:11;:19::i;:::-;31787:54;;;;-1:-1:-1;;;31787:54:0;;;;;;;:::i;:::-;31928:50;31938:6;:18;;;31958:6;:19;;;31928:9;:50::i;:::-;31927:51;31919:107;;;;-1:-1:-1;;;31919:107:0;;;;;;;:::i;:::-;32123:52;32135:6;:18;;;32155:6;:19;;;32123:11;:52::i;:::-;32384:18;;32370:33;;;;:13;:33;;;;;;;;;:45;;;;32271:14;;;;32238:18;;32300:19;;;;32334:13;;;;32191:236;;-1:-1:-1;;;;;32370:45:0;;;;32191:236;;;;;32213:10;;32191:236;;;;32238:18;32300:19;32191:236;:::i;:::-;;;;;;;;31646:789;:::o;3765:181::-;3823:7;3855:5;;;3879:6;;;;3871:46;;;;-1:-1:-1;;;3871:46:0;;;;;;;:::i;11578:177::-;11661:86;11681:5;11711:23;;;11736:2;11740:5;11688:58;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;11688:58:0;;;;;;;;;;;;;;-1:-1:-1;;;;;11688:58:0;-1:-1:-1;;;;;;11688:58:0;;;;;;;;;;11661:19;:86::i;:::-;11578:177;;;:::o;16842:106::-;16930:10;16842:106;:::o;30995:570::-;31198:21;31222:26;;;:13;:26;;;;;;;;31259:30;;;31300:18;;;:40;;-1:-1:-1;;;;;;31300:40:0;-1:-1:-1;;;;;31300:40:0;;;;;31351:26;;31222;;31351;;:15;;;;:26;;;;:::i;:::-;;31440:11;-1:-1:-1;;;;;31395:69:0;31409:11;31395:69;31422:16;31453:10;31395:69;;;;;;;:::i;:::-;;;;;;;;31477:18;;;;:80;;-1:-1:-1;;;;;31477:18:0;31513:10;31533:4;31540:16;31477:35;:80::i;:::-;30995:570;;;;;;:::o;30523:344::-;30606:24;30777:26;;;:13;:26;;;;;;;;30648:3;30633:18;;30777:44;;;;;;;;;;30838:1;30688:18;;;;30838:20;;;;30777:82;;;30717:142;;30523:344::o;13622:1115::-;14227:27;14235:5;-1:-1:-1;;;;;14227:25:0;;:27::i;:::-;14219:71;;;;-1:-1:-1;;;14219:71:0;;;;;;;:::i;:::-;14364:12;14378:23;14413:5;-1:-1:-1;;;;;14405:19:0;14425:4;14405:25;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;14363:67;;;;14449:7;14441:52;;;;-1:-1:-1;;;14441:52:0;;;;;;;:::i;:::-;14510:17;;:21;14506:224;;14652:10;14641:30;;;;;;;;;;;;:::i;:::-;14633:85;;;;-1:-1:-1;;;14633:85:0;;;;;;;:::i;11763:205::-;11864:96;11884:5;11914:27;;;11943:4;11949:2;11953:5;11891:68;;;;;;;;;;:::i;8998:619::-;9058:4;9526:20;;9369:66;9566:23;;;;;;:42;;-1:-1:-1;9593:15:0;;;9566:42;9558:51;8998:619;-1:-1:-1;;;;8998:619:0:o;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;5:130;72:20;;-1:-1;;;;;21303:54;;23166:35;;23156:2;;23215:1;;23205:12;2428:1035;;2539:4;2527:9;2522:3;2518:19;2514:30;2511:2;;;-1:-1;;2547:12;2511:2;2575:20;2539:4;2575:20;:::i;:::-;2566:29;;3550:6;3537:20;2666:16;2659:75;2797:2;;2855:9;2851:22;3537:20;2797:2;2816:5;2812:16;2805:75;2949:2;3007:9;3003:22;3537:20;2949:2;2968:5;2964:16;2957:75;3129:49;3174:3;3096:2;3154:9;3150:22;3129:49;:::i;:::-;3096:2;3115:5;3111:16;3104:75;3275:3;3264:9;3260:19;3247:33;3300:18;3292:6;3289:30;3286:2;;;-1:-1;;3322:12;3286:2;3413:22;;270:4;258:17;;254:27;-1:-1;244:2;;-1:-1;;285:12;244:2;332:6;319:20;354:80;369:64;426:6;369:64;:::i;:::-;354:80;:::i;:::-;462:21;;;519:14;;;;494:17;;;608;;;599:27;;;;596:36;-1:-1;593:2;;;-1:-1;;635:12;593:2;-1:-1;661:10;;655:206;680:6;677:1;674:13;655:206;;;1870:20;;748:50;;702:1;695:9;;;;;812:14;;;;840;;655:206;;;-1:-1;3275:3;3349:16;;3342:100;-1:-1;3353:5;;2505:958;-1:-1;;;;;2505:958::o;3607:241::-;;3711:2;3699:9;3690:7;3686:23;3682:32;3679:2;;;-1:-1;;3717:12;3679:2;3779:53;3824:7;3800:22;3779:53;:::i;3855:366::-;;;3976:2;3964:9;3955:7;3951:23;3947:32;3944:2;;;-1:-1;;3982:12;3944:2;4044:53;4089:7;4065:22;4044:53;:::i;:::-;4034:63;4134:2;4173:22;;;;3537:20;;-1:-1;;;3938:283::o;4228:421::-;;4379:2;;4367:9;4358:7;4354:23;4350:32;4347:2;;;-1:-1;;4385:12;4347:2;4443:17;4430:31;4481:18;4473:6;4470:30;4467:2;;;-1:-1;;4503:12;4467:2;4601:22;;1048:4;1036:17;;1032:27;-1:-1;1022:2;;-1:-1;;1063:12;1022:2;1110:6;1097:20;1132:102;1147:86;1226:6;1147:86;:::i;1132:102::-;1262:21;;;1319:14;;;;1294:17;;;-1:-1;1399:255;1424:6;1421:1;1418:13;1399:255;;;1531:59;1586:3;4379:2;1507:3;1494:17;1298:6;1482:30;;1531:59;:::i;:::-;1519:72;;1605:14;;;;1633;;;;1446:1;1439:9;1399:255;;;-1:-1;4523:110;;4341:308;-1:-1;;;;;;;;4341:308::o;4656:257::-;;4768:2;4756:9;4747:7;4743:23;4739:32;4736:2;;;-1:-1;;4774:12;4736:2;1749:6;1743:13;23312:5;21136:13;21129:21;23290:5;23287:32;23277:2;;-1:-1;;23323:12;4920:371;;5046:2;5034:9;5025:7;5021:23;5017:32;5014:2;;;-1:-1;;5052:12;5014:2;5110:17;5097:31;5148:18;5140:6;5137:30;5134:2;;;-1:-1;;5170:12;5134:2;5200:75;5267:7;5258:6;5247:9;5243:22;5200:75;:::i;5298:241::-;;5402:2;5390:9;5381:7;5377:23;5373:32;5370:2;;;-1:-1;;5408:12;5370:2;-1:-1;3537:20;;5364:175;-1:-1;5364:175::o;5546:723::-;;;;;5711:3;5699:9;5690:7;5686:23;5682:33;5679:2;;;-1:-1;;5718:12;5679:2;3550:6;3537:20;5770:63;;5870:2;;5913:9;5909:22;72:20;97:33;124:5;97:33;:::i;:::-;5878:63;-1:-1;5978:2;6017:22;;1870:20;;-1:-1;6114:2;6099:18;;6086:32;6138:18;6127:30;;;6124:2;;;-1:-1;;6160:12;6124:2;6236:6;6225:9;6221:22;;;2043:3;2036:4;2028:6;2024:17;2020:27;2010:2;;-1:-1;;2051:12;2010:2;2098:6;2085:20;6138:18;20197:6;20194:30;20191:2;;;-1:-1;;20227:12;20191:2;2120:65;20300:9;20281:17;;-1:-1;;20277:33;20358:15;;2120:65;:::i;:::-;2111:74;;2205:6;2198:5;2191:21;2309:3;5870:2;2300:6;2233;2291:16;;2288:25;2285:2;;;-1:-1;;2316:12;2285:2;22191:6;5870:2;2233:6;2229:17;5870:2;2267:5;2263:16;22168:30;22229:16;;;;;22222:27;;;;5673:596;;;;-1:-1;5673:596;;-1:-1;;5673:596::o;6276:366::-;;;6397:2;6385:9;6376:7;6372:23;6368:32;6365:2;;;-1:-1;;6403:12;6365:2;-1:-1;;3537:20;;;6555:2;6594:22;;;3537:20;;-1:-1;6359:283::o;11472:531::-;23079:2;23075:14;;;;-1:-1;;23075:14;7007:58;;11753:2;11744:12;;7259:37;;;;11855:12;;;7259:37;11966:12;;;11644:359::o;12010:392::-;7259:37;;;12263:2;12254:12;;7259:37;12365:12;;;12154:248::o;12409:271::-;;7627:5;20477:12;7738:52;7783:6;7778:3;7771:4;7764:5;7760:16;7738:52;:::i;:::-;7802:16;;;;;12543:137;-1:-1;;12543:137::o;12687:222::-;-1:-1;;;;;21303:54;;;;6869:37;;12814:2;12799:18;;12785:124::o;13161:444::-;-1:-1;;;;;21303:54;;;6869:37;;21303:54;;;;13508:2;13493:18;;6869:37;13591:2;13576:18;;7259:37;;;;13344:2;13329:18;;13315:290::o;13612:333::-;-1:-1;;;;;21303:54;;;;6869:37;;13931:2;13916:18;;7259:37;13767:2;13752:18;;13738:207::o;13952:210::-;21136:13;;21129:21;7142:34;;14073:2;14058:18;;14044:118::o;14169:558::-;;7289:5;7266:3;7259:37;21314:42;;;;;7970:5;21303:54;14562:2;14551:9;14547:18;7914:63;14385:2;14599;14588:9;14584:18;14577:48;8134:5;20477:12;20916:6;14385:2;14374:9;14370:18;20904:19;8228:52;8273:6;20944:14;14374:9;20944:14;14562:2;8254:5;8250:16;8228:52;:::i;:::-;20300:9;22968:14;-1:-1;;22964:28;8292:39;;;;20944:14;8292:39;;14356:371;-1:-1;;;;14356:371::o;14734:416::-;14934:2;14948:47;;;8568:2;14919:18;;;20904:19;8604:34;20944:14;;;8584:55;-1:-1;;;8659:12;;;8652:30;8701:12;;;14905:245::o;15157:416::-;15357:2;15371:47;;;8952:2;15342:18;;;20904:19;-1:-1;;;20944:14;;;8968:45;9032:12;;;15328:245::o;15580:416::-;15780:2;15794:47;;;9283:2;15765:18;;;20904:19;9319:29;20944:14;;;9299:50;9368:12;;;15751:245::o;16003:416::-;16203:2;16217:47;;;16188:18;;;20904:19;9655:34;20944:14;;;9635:55;9709:12;;;16174:245::o;16426:416::-;16626:2;16640:47;;;16611:18;;;20904:19;9996:34;20944:14;;;9976:55;10050:12;;;16597:245::o;16849:416::-;17049:2;17063:47;;;10301:2;17034:18;;;20904:19;10337:34;20944:14;;;10317:55;-1:-1;;;10392:12;;;10385:35;10439:12;;;17020:245::o;17272:416::-;17472:2;17486:47;;;10690:2;17457:18;;;20904:19;10726:34;20944:14;;;10706:55;-1:-1;;;10781:12;;;10774:34;10827:12;;;17443:245::o;17695:416::-;17895:2;17909:47;;;11078:2;17880:18;;;20904:19;11114:33;20944:14;;;11094:54;11167:12;;;17866:245::o;18118:222::-;7259:37;;;18245:2;18230:18;;18216:124::o;18347:349::-;7259:37;;;-1:-1;;;;;21303:54;18682:2;18667:18;;6728:58;18510:2;18495:18;;18481:215::o;18703:444::-;7259:37;;;19050:2;19035:18;;7259:37;;;;19133:2;19118:18;;7259:37;18886:2;18871:18;;18857:290::o;19154:256::-;19216:2;19210:9;19242:17;;;19317:18;19302:34;;19338:22;;;19299:62;19296:2;;;19374:1;;19364:12;19296:2;19216;19383:22;19194:216;;-1:-1;19194:216::o;19417:304::-;;19576:18;19568:6;19565:30;19562:2;;;-1:-1;;19598:12;19562:2;-1:-1;19643:4;19631:17;;;19696:15;;19499:222::o;22264:268::-;22329:1;22336:101;22350:6;22347:1;22344:13;22336:101;;;22417:11;;;22411:18;22398:11;;;22391:39;22372:2;22365:10;22336:101;;;22452:6;22449:1;22446:13;22443:2;;;-1:-1;;22329:1;22499:16;;22492:27;22313:219::o;23107:117::-;-1:-1;;;;;21303:54;;23166:35;;23156:2;;23215:1;;23205:12
Swarm Source
ipfs://fe58190692178baf85e1671709fc6626f66d4db3a5ad895137661829006e1787
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 26 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
ETH | 100.00% | $1 | 4 | $4 |
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.