Source Code
| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 107558363 | 869 days ago | 0 ETH | ||||
| 107558353 | 869 days ago | 0 ETH | ||||
| 107558340 | 869 days ago | 0 ETH | ||||
| 107558291 | 869 days ago | 0 ETH | ||||
| 107558286 | 869 days ago | 0 ETH | ||||
| 107558273 | 869 days ago | 0 ETH | ||||
| 107558213 | 869 days ago | 0 ETH | ||||
| 107558149 | 869 days ago | 0 ETH | ||||
| 107558026 | 869 days ago | 0 ETH | ||||
| 107558020 | 869 days ago | 0 ETH | ||||
| 107558008 | 869 days ago | 0 ETH | ||||
| 107558006 | 869 days ago | 0 ETH | ||||
| 107557986 | 869 days ago | 0 ETH | ||||
| 107557982 | 869 days ago | 0 ETH | ||||
| 107557967 | 869 days ago | 0 ETH | ||||
| 107557951 | 869 days ago | 0 ETH | ||||
| 107557950 | 869 days ago | 0 ETH | ||||
| 107557844 | 869 days ago | 0 ETH | ||||
| 107557830 | 869 days ago | 0 ETH | ||||
| 107557779 | 869 days ago | 0 ETH | ||||
| 107557715 | 869 days ago | 0 ETH | ||||
| 107557707 | 869 days ago | 0 ETH | ||||
| 107557703 | 869 days ago | 0 ETH | ||||
| 107557702 | 869 days ago | 0 ETH | ||||
| 107557697 | 869 days ago | 0 ETH |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
MerkleTreeManager
Compiler Version
v0.8.17+commit.8df45f5f
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity 0.8.17;
import {ProposedOwnableUpgradeable} from "../shared/ProposedOwnableUpgradeable.sol";
import {MerkleLib} from "./libraries/MerkleLib.sol";
/**
* @title MerkleTreeManager
* @notice Contains a Merkle tree instance and exposes read/write functions for the tree.
* @dev On the hub domain there are two MerkleTreeManager contracts, one for the hub and one for the MainnetSpokeConnector.
*/
contract MerkleTreeManager is ProposedOwnableUpgradeable {
// ========== Custom Errors ===========
error MerkleTreeManager__setArborist_zeroAddress();
error MerkleTreeManager__setArborist_alreadyArborist();
// ============ Events ============
event ArboristUpdated(address previous, address updated);
event LeafInserted(bytes32 root, uint256 count, bytes32 leaf);
event LeavesInserted(bytes32 root, uint256 count, bytes32[] leaves);
// ============ Libraries ============
using MerkleLib for MerkleLib.Tree;
// ============ Public Storage ============
/**
* @notice Core data structure with which this contract is tasked with keeping custody.
* Writable only by the designated arborist.
*/
MerkleLib.Tree public tree;
/**
* @notice The arborist contract that has permission to write to this tree.
* @dev This could be the root manager contract or a spoke connector contract, for example.
*/
address public arborist;
// ============ Modifiers ============
modifier onlyArborist() {
require(arborist == msg.sender, "!arborist");
_;
}
// ============ Getters ============
/**
* @notice Returns the current branch.
*/
function branch() public view returns (bytes32[32] memory) {
return tree.branch;
}
/**
* @notice Calculates and returns the current root.
*/
function root() public view returns (bytes32) {
return tree.root();
}
/**
* @notice Returns the number of inserted leaves in the tree (current index).
*/
function count() public view returns (uint256) {
return tree.count;
}
/**
* @notice Convenience getter: returns the root and count.
*/
function rootAndCount() public view returns (bytes32, uint256) {
return (tree.root(), tree.count);
}
// ======== Initializer =========
function initialize(address _arborist) public initializer {
__MerkleTreeManager_init(_arborist);
__ProposedOwnable_init();
}
/**
* @dev Initializes MerkleTreeManager instance. Sets the msg.sender as the initial permissioned
*/
function __MerkleTreeManager_init(address _arborist) internal onlyInitializing {
__MerkleTreeManager_init_unchained(_arborist);
}
function __MerkleTreeManager_init_unchained(address _arborist) internal onlyInitializing {
arborist = _arborist;
}
// ============ Admin Functions ==============
/**
* @notice Method for the current arborist to assign write permissions to a new arborist.
* @param newArborist The new address to set as the current arborist.
*/
function setArborist(address newArborist) external onlyOwner {
if (newArborist == address(0)) revert MerkleTreeManager__setArborist_zeroAddress();
address current = arborist;
if (current == newArborist) revert MerkleTreeManager__setArborist_alreadyArborist();
// Emit updated event
emit ArboristUpdated(current, newArborist);
arborist = newArborist;
}
/**
* @notice Remove ability to renounce ownership
* @dev Renounce ownership should be impossible as long as there is a possibility the
* arborist may change.
*/
function renounceOwnership() public virtual override onlyOwner {}
// ========= Public Functions =========
/**
* @notice Inserts the given leaves into the tree.
* @param leaves The leaves to be inserted into the tree.
* @return _root Current root for convenience.
* @return _count Current node count (i.e. number of indices) AFTER the insertion of the new leaf,
* provided for convenience.
*/
function insert(bytes32[] memory leaves) public onlyArborist returns (bytes32 _root, uint256 _count) {
// For > 1 leaf, considerably more efficient to put this tree into memory, conduct operations,
// then re-assign it to storage - *especially* if we have multiple leaves to insert.
MerkleLib.Tree memory _tree = tree;
uint256 leafCount = leaves.length;
for (uint256 i; i < leafCount; ) {
// Insert the new node (using in-memory method).
_tree = _tree.insert(leaves[i]);
unchecked {
++i;
}
}
// Write the newly updated tree to storage.
tree = _tree;
// Get return details for convenience.
_count = _tree.count;
// NOTE: Root calculation method currently reads from storage only.
_root = tree.root();
emit LeavesInserted(_root, _count, leaves);
}
/**
* @notice Inserts the given leaf into the tree.
* @param leaf The leaf to be inserted into the tree.
* @return _root Current root for convenience.
* @return _count Current node count (i.e. number of indices) AFTER the insertion of the new leaf,
* provided for convenience.
*/
function insert(bytes32 leaf) public onlyArborist returns (bytes32 _root, uint256 _count) {
// Insert the new node.
tree = tree.insert(leaf);
_count = tree.count;
_root = tree.root();
emit LeafInserted(_root, _count, leaf);
}
// ============ Upgrade Gap ============
uint256[48] private __GAP; // gap for upgrade safety
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
* constructor.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: setting the version to 255 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized < type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
/**
* @dev Internal function that returns the initialized version. Returns `_initialized`
*/
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
/**
* @dev Internal function that returns the initialized version. Returns `_initializing`
*/
function _isInitializing() internal view returns (bool) {
return _initializing;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @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
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "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");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, 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) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// 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
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity 0.8.17;
/**
* @title MerkleLib
* @author Illusory Systems Inc.
* @notice An incremental merkle tree modeled on the eth2 deposit contract.
**/
library MerkleLib {
// ========== Custom Errors ===========
error MerkleLib__insert_treeIsFull();
// ============ Constants =============
uint256 internal constant TREE_DEPTH = 32;
uint256 internal constant MAX_LEAVES = 2**TREE_DEPTH - 1;
/**
* @dev Z_i represent the hash values at different heights for a binary tree with leaf values equal to `0`.
* (e.g. Z_1 is the keccak256 hash of (0x0, 0x0), Z_2 is the keccak256 hash of (Z_1, Z_1), etc...)
* Z_0 is the bottom of the 33-layer tree, Z_32 is the top (i.e. root).
* Used to shortcut calculation in root calculation methods below.
*/
bytes32 internal constant Z_0 = hex"0000000000000000000000000000000000000000000000000000000000000000";
bytes32 internal constant Z_1 = hex"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5";
bytes32 internal constant Z_2 = hex"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30";
bytes32 internal constant Z_3 = hex"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85";
bytes32 internal constant Z_4 = hex"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344";
bytes32 internal constant Z_5 = hex"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d";
bytes32 internal constant Z_6 = hex"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968";
bytes32 internal constant Z_7 = hex"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83";
bytes32 internal constant Z_8 = hex"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af";
bytes32 internal constant Z_9 = hex"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0";
bytes32 internal constant Z_10 = hex"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5";
bytes32 internal constant Z_11 = hex"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892";
bytes32 internal constant Z_12 = hex"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c";
bytes32 internal constant Z_13 = hex"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb";
bytes32 internal constant Z_14 = hex"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc";
bytes32 internal constant Z_15 = hex"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2";
bytes32 internal constant Z_16 = hex"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f";
bytes32 internal constant Z_17 = hex"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a";
bytes32 internal constant Z_18 = hex"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0";
bytes32 internal constant Z_19 = hex"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0";
bytes32 internal constant Z_20 = hex"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2";
bytes32 internal constant Z_21 = hex"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9";
bytes32 internal constant Z_22 = hex"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377";
bytes32 internal constant Z_23 = hex"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652";
bytes32 internal constant Z_24 = hex"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef";
bytes32 internal constant Z_25 = hex"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d";
bytes32 internal constant Z_26 = hex"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0";
bytes32 internal constant Z_27 = hex"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e";
bytes32 internal constant Z_28 = hex"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e";
bytes32 internal constant Z_29 = hex"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322";
bytes32 internal constant Z_30 = hex"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735";
bytes32 internal constant Z_31 = hex"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9";
bytes32 internal constant Z_32 = hex"27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757";
// ============= Structs ==============
/**
* @notice Struct representing incremental merkle tree. Contains current
* branch and the number of inserted leaves in the tree.
**/
struct Tree {
bytes32[TREE_DEPTH] branch;
uint256 count;
}
// ========= Write Methods =========
/**
* @notice Inserts a given node (leaf) into merkle tree. Operates on an in-memory tree and
* returns an updated version of that tree.
* @dev Reverts if the tree is already full.
* @param node Element to insert into tree.
* @return Tree Updated tree.
**/
function insert(Tree memory tree, bytes32 node) internal pure returns (Tree memory) {
// Update tree.count to increase the current count by 1 since we'll be including a new node.
uint256 size = ++tree.count;
if (size > MAX_LEAVES) revert MerkleLib__insert_treeIsFull();
// Loop starting at 0, ending when we've finished inserting the node (i.e. hashing it) into
// the active branch. Each loop we cut size in half, hashing the inserted node up the active
// branch along the way.
for (uint256 i; i < TREE_DEPTH; ) {
// Check if the current size is odd; if so, we set this index in the branch to be the node.
if ((size & 1) == 1) {
// If i > 0, then this node will be a hash of the original node with every layer up
// until layer `i`.
tree.branch[i] = node;
return tree;
}
// If the size is not yet odd, we hash the current index in the tree branch with the node.
node = keccak256(abi.encodePacked(tree.branch[i], node));
size >>= 1; // Cut size in half (statement equivalent to: `size /= 2`).
unchecked {
++i;
}
}
// As the loop should always end prematurely with the `return` statement, this code should
// be unreachable. We revert here just to be safe.
revert MerkleLib__insert_treeIsFull();
}
// ========= Read Methods =========
/**
* @notice Calculates and returns tree's current root.
* @return _current bytes32 root.
**/
function root(Tree storage tree) internal view returns (bytes32 _current) {
uint256 _index = tree.count;
if (_index == 0) {
return Z_32;
}
uint256 i;
assembly {
let TREE_SLOT := tree.slot
for {
} true {
} {
for {
} true {
} {
if and(_index, 1) {
mstore(0, sload(TREE_SLOT))
mstore(0x20, Z_0)
_current := keccak256(0, 0x40)
break
}
if and(_index, shl(1, 1)) {
mstore(0, sload(add(TREE_SLOT, 1)))
mstore(0x20, Z_1)
_current := keccak256(0, 0x40)
i := 1
break
}
if and(_index, shl(2, 1)) {
mstore(0, sload(add(TREE_SLOT, 2)))
mstore(0x20, Z_2)
_current := keccak256(0, 0x40)
i := 2
break
}
if and(_index, shl(3, 1)) {
mstore(0, sload(add(TREE_SLOT, 3)))
mstore(0x20, Z_3)
_current := keccak256(0, 0x40)
i := 3
break
}
if and(_index, shl(4, 1)) {
mstore(0, sload(add(TREE_SLOT, 4)))
mstore(0x20, Z_4)
_current := keccak256(0, 0x40)
i := 4
break
}
if and(_index, shl(5, 1)) {
mstore(0, sload(add(TREE_SLOT, 5)))
mstore(0x20, Z_5)
_current := keccak256(0, 0x40)
i := 5
break
}
if and(_index, shl(6, 1)) {
mstore(0, sload(add(TREE_SLOT, 6)))
mstore(0x20, Z_6)
_current := keccak256(0, 0x40)
i := 6
break
}
if and(_index, shl(7, 1)) {
mstore(0, sload(add(TREE_SLOT, 7)))
mstore(0x20, Z_7)
_current := keccak256(0, 0x40)
i := 7
break
}
if and(_index, shl(8, 1)) {
mstore(0, sload(add(TREE_SLOT, 8)))
mstore(0x20, Z_8)
_current := keccak256(0, 0x40)
i := 8
break
}
if and(_index, shl(9, 1)) {
mstore(0, sload(add(TREE_SLOT, 9)))
mstore(0x20, Z_9)
_current := keccak256(0, 0x40)
i := 9
break
}
if and(_index, shl(10, 1)) {
mstore(0, sload(add(TREE_SLOT, 10)))
mstore(0x20, Z_10)
_current := keccak256(0, 0x40)
i := 10
break
}
if and(_index, shl(11, 1)) {
mstore(0, sload(add(TREE_SLOT, 11)))
mstore(0x20, Z_11)
_current := keccak256(0, 0x40)
i := 11
break
}
if and(_index, shl(12, 1)) {
mstore(0, sload(add(TREE_SLOT, 12)))
mstore(0x20, Z_12)
_current := keccak256(0, 0x40)
i := 12
break
}
if and(_index, shl(13, 1)) {
mstore(0, sload(add(TREE_SLOT, 13)))
mstore(0x20, Z_13)
_current := keccak256(0, 0x40)
i := 13
break
}
if and(_index, shl(14, 1)) {
mstore(0, sload(add(TREE_SLOT, 14)))
mstore(0x20, Z_14)
_current := keccak256(0, 0x40)
i := 14
break
}
if and(_index, shl(15, 1)) {
mstore(0, sload(add(TREE_SLOT, 15)))
mstore(0x20, Z_15)
_current := keccak256(0, 0x40)
i := 15
break
}
if and(_index, shl(16, 1)) {
mstore(0, sload(add(TREE_SLOT, 16)))
mstore(0x20, Z_16)
_current := keccak256(0, 0x40)
i := 16
break
}
if and(_index, shl(17, 1)) {
mstore(0, sload(add(TREE_SLOT, 17)))
mstore(0x20, Z_17)
_current := keccak256(0, 0x40)
i := 17
break
}
if and(_index, shl(18, 1)) {
mstore(0, sload(add(TREE_SLOT, 18)))
mstore(0x20, Z_18)
_current := keccak256(0, 0x40)
i := 18
break
}
if and(_index, shl(19, 1)) {
mstore(0, sload(add(TREE_SLOT, 19)))
mstore(0x20, Z_19)
_current := keccak256(0, 0x40)
i := 19
break
}
if and(_index, shl(20, 1)) {
mstore(0, sload(add(TREE_SLOT, 20)))
mstore(0x20, Z_20)
_current := keccak256(0, 0x40)
i := 20
break
}
if and(_index, shl(21, 1)) {
mstore(0, sload(add(TREE_SLOT, 21)))
mstore(0x20, Z_21)
_current := keccak256(0, 0x40)
i := 21
break
}
if and(_index, shl(22, 1)) {
mstore(0, sload(add(TREE_SLOT, 22)))
mstore(0x20, Z_22)
_current := keccak256(0, 0x40)
i := 22
break
}
if and(_index, shl(23, 1)) {
mstore(0, sload(add(TREE_SLOT, 23)))
mstore(0x20, Z_23)
_current := keccak256(0, 0x40)
i := 23
break
}
if and(_index, shl(24, 1)) {
mstore(0, sload(add(TREE_SLOT, 24)))
mstore(0x20, Z_24)
_current := keccak256(0, 0x40)
i := 24
break
}
if and(_index, shl(25, 1)) {
mstore(0, sload(add(TREE_SLOT, 25)))
mstore(0x20, Z_25)
_current := keccak256(0, 0x40)
i := 25
break
}
if and(_index, shl(26, 1)) {
mstore(0, sload(add(TREE_SLOT, 26)))
mstore(0x20, Z_26)
_current := keccak256(0, 0x40)
i := 26
break
}
if and(_index, shl(27, 1)) {
mstore(0, sload(add(TREE_SLOT, 27)))
mstore(0x20, Z_27)
_current := keccak256(0, 0x40)
i := 27
break
}
if and(_index, shl(28, 1)) {
mstore(0, sload(add(TREE_SLOT, 28)))
mstore(0x20, Z_28)
_current := keccak256(0, 0x40)
i := 28
break
}
if and(_index, shl(29, 1)) {
mstore(0, sload(add(TREE_SLOT, 29)))
mstore(0x20, Z_29)
_current := keccak256(0, 0x40)
i := 29
break
}
if and(_index, shl(30, 1)) {
mstore(0, sload(add(TREE_SLOT, 30)))
mstore(0x20, Z_30)
_current := keccak256(0, 0x40)
i := 30
break
}
if and(_index, shl(31, 1)) {
mstore(0, sload(add(TREE_SLOT, 31)))
mstore(0x20, Z_31)
_current := keccak256(0, 0x40)
i := 31
break
}
_current := Z_32
i := 32
break
}
if gt(i, 30) {
break
}
{
if lt(i, 1) {
switch and(_index, shl(1, 1))
case 0 {
mstore(0, _current)
mstore(0x20, Z_1)
}
default {
mstore(0, sload(add(TREE_SLOT, 1)))
mstore(0x20, _current)
}
_current := keccak256(0, 0x40)
}
if lt(i, 2) {
switch and(_index, shl(2, 1))
case 0 {
mstore(0, _current)
mstore(0x20, Z_2)
}
default {
mstore(0, sload(add(TREE_SLOT, 2)))
mstore(0x20, _current)
}
_current := keccak256(0, 0x40)
}
if lt(i, 3) {
switch and(_index, shl(3, 1))
case 0 {
mstore(0, _current)
mstore(0x20, Z_3)
}
default {
mstore(0, sload(add(TREE_SLOT, 3)))
mstore(0x20, _current)
}
_current := keccak256(0, 0x40)
}
if lt(i, 4) {
switch and(_index, shl(4, 1))
case 0 {
mstore(0, _current)
mstore(0x20, Z_4)
}
default {
mstore(0, sload(add(TREE_SLOT, 4)))
mstore(0x20, _current)
}
_current := keccak256(0, 0x40)
}
if lt(i, 5) {
switch and(_index, shl(5, 1))
case 0 {
mstore(0, _current)
mstore(0x20, Z_5)
}
default {
mstore(0, sload(add(TREE_SLOT, 5)))
mstore(0x20, _current)
}
_current := keccak256(0, 0x40)
}
if lt(i, 6) {
switch and(_index, shl(6, 1))
case 0 {
mstore(0, _current)
mstore(0x20, Z_6)
}
default {
mstore(0, sload(add(TREE_SLOT, 6)))
mstore(0x20, _current)
}
_current := keccak256(0, 0x40)
}
if lt(i, 7) {
switch and(_index, shl(7, 1))
case 0 {
mstore(0, _current)
mstore(0x20, Z_7)
}
default {
mstore(0, sload(add(TREE_SLOT, 7)))
mstore(0x20, _current)
}
_current := keccak256(0, 0x40)
}
if lt(i, 8) {
switch and(_index, shl(8, 1))
case 0 {
mstore(0, _current)
mstore(0x20, Z_8)
}
default {
mstore(0, sload(add(TREE_SLOT, 8)))
mstore(0x20, _current)
}
_current := keccak256(0, 0x40)
}
if lt(i, 9) {
switch and(_index, shl(9, 1))
case 0 {
mstore(0, _current)
mstore(0x20, Z_9)
}
default {
mstore(0, sload(add(TREE_SLOT, 9)))
mstore(0x20, _current)
}
_current := keccak256(0, 0x40)
}
if lt(i, 10) {
switch and(_index, shl(10, 1))
case 0 {
mstore(0, _current)
mstore(0x20, Z_10)
}
default {
mstore(0, sload(add(TREE_SLOT, 10)))
mstore(0x20, _current)
}
_current := keccak256(0, 0x40)
}
if lt(i, 11) {
switch and(_index, shl(11, 1))
case 0 {
mstore(0, _current)
mstore(0x20, Z_11)
}
default {
mstore(0, sload(add(TREE_SLOT, 11)))
mstore(0x20, _current)
}
_current := keccak256(0, 0x40)
}
if lt(i, 12) {
switch and(_index, shl(12, 1))
case 0 {
mstore(0, _current)
mstore(0x20, Z_12)
}
default {
mstore(0, sload(add(TREE_SLOT, 12)))
mstore(0x20, _current)
}
_current := keccak256(0, 0x40)
}
if lt(i, 13) {
switch and(_index, shl(13, 1))
case 0 {
mstore(0, _current)
mstore(0x20, Z_13)
}
default {
mstore(0, sload(add(TREE_SLOT, 13)))
mstore(0x20, _current)
}
_current := keccak256(0, 0x40)
}
if lt(i, 14) {
switch and(_index, shl(14, 1))
case 0 {
mstore(0, _current)
mstore(0x20, Z_14)
}
default {
mstore(0, sload(add(TREE_SLOT, 14)))
mstore(0x20, _current)
}
_current := keccak256(0, 0x40)
}
if lt(i, 15) {
switch and(_index, shl(15, 1))
case 0 {
mstore(0, _current)
mstore(0x20, Z_15)
}
default {
mstore(0, sload(add(TREE_SLOT, 15)))
mstore(0x20, _current)
}
_current := keccak256(0, 0x40)
}
if lt(i, 16) {
switch and(_index, shl(16, 1))
case 0 {
mstore(0, _current)
mstore(0x20, Z_16)
}
default {
mstore(0, sload(add(TREE_SLOT, 16)))
mstore(0x20, _current)
}
_current := keccak256(0, 0x40)
}
if lt(i, 17) {
switch and(_index, shl(17, 1))
case 0 {
mstore(0, _current)
mstore(0x20, Z_17)
}
default {
mstore(0, sload(add(TREE_SLOT, 17)))
mstore(0x20, _current)
}
_current := keccak256(0, 0x40)
}
if lt(i, 18) {
switch and(_index, shl(18, 1))
case 0 {
mstore(0, _current)
mstore(0x20, Z_18)
}
default {
mstore(0, sload(add(TREE_SLOT, 18)))
mstore(0x20, _current)
}
_current := keccak256(0, 0x40)
}
if lt(i, 19) {
switch and(_index, shl(19, 1))
case 0 {
mstore(0, _current)
mstore(0x20, Z_19)
}
default {
mstore(0, sload(add(TREE_SLOT, 19)))
mstore(0x20, _current)
}
_current := keccak256(0, 0x40)
}
if lt(i, 20) {
switch and(_index, shl(20, 1))
case 0 {
mstore(0, _current)
mstore(0x20, Z_20)
}
default {
mstore(0, sload(add(TREE_SLOT, 20)))
mstore(0x20, _current)
}
_current := keccak256(0, 0x40)
}
if lt(i, 21) {
switch and(_index, shl(21, 1))
case 0 {
mstore(0, _current)
mstore(0x20, Z_21)
}
default {
mstore(0, sload(add(TREE_SLOT, 21)))
mstore(0x20, _current)
}
_current := keccak256(0, 0x40)
}
if lt(i, 22) {
switch and(_index, shl(22, 1))
case 0 {
mstore(0, _current)
mstore(0x20, Z_22)
}
default {
mstore(0, sload(add(TREE_SLOT, 22)))
mstore(0x20, _current)
}
_current := keccak256(0, 0x40)
}
if lt(i, 23) {
switch and(_index, shl(23, 1))
case 0 {
mstore(0, _current)
mstore(0x20, Z_23)
}
default {
mstore(0, sload(add(TREE_SLOT, 23)))
mstore(0x20, _current)
}
_current := keccak256(0, 0x40)
}
if lt(i, 24) {
switch and(_index, shl(24, 1))
case 0 {
mstore(0, _current)
mstore(0x20, Z_24)
}
default {
mstore(0, sload(add(TREE_SLOT, 24)))
mstore(0x20, _current)
}
_current := keccak256(0, 0x40)
}
if lt(i, 25) {
switch and(_index, shl(25, 1))
case 0 {
mstore(0, _current)
mstore(0x20, Z_25)
}
default {
mstore(0, sload(add(TREE_SLOT, 25)))
mstore(0x20, _current)
}
_current := keccak256(0, 0x40)
}
if lt(i, 26) {
switch and(_index, shl(26, 1))
case 0 {
mstore(0, _current)
mstore(0x20, Z_26)
}
default {
mstore(0, sload(add(TREE_SLOT, 26)))
mstore(0x20, _current)
}
_current := keccak256(0, 0x40)
}
if lt(i, 27) {
switch and(_index, shl(27, 1))
case 0 {
mstore(0, _current)
mstore(0x20, Z_27)
}
default {
mstore(0, sload(add(TREE_SLOT, 27)))
mstore(0x20, _current)
}
_current := keccak256(0, 0x40)
}
if lt(i, 28) {
switch and(_index, shl(28, 1))
case 0 {
mstore(0, _current)
mstore(0x20, Z_28)
}
default {
mstore(0, sload(add(TREE_SLOT, 28)))
mstore(0x20, _current)
}
_current := keccak256(0, 0x40)
}
if lt(i, 29) {
switch and(_index, shl(29, 1))
case 0 {
mstore(0, _current)
mstore(0x20, Z_29)
}
default {
mstore(0, sload(add(TREE_SLOT, 29)))
mstore(0x20, _current)
}
_current := keccak256(0, 0x40)
}
if lt(i, 30) {
switch and(_index, shl(30, 1))
case 0 {
mstore(0, _current)
mstore(0x20, Z_30)
}
default {
mstore(0, sload(add(TREE_SLOT, 30)))
mstore(0x20, _current)
}
_current := keccak256(0, 0x40)
}
if lt(i, 31) {
switch and(_index, shl(31, 1))
case 0 {
mstore(0, _current)
mstore(0x20, Z_31)
}
default {
mstore(0, sload(add(TREE_SLOT, 31)))
mstore(0x20, _current)
}
_current := keccak256(0, 0x40)
}
}
break
}
}
}
/**
* @notice Calculates and returns the merkle root for the given leaf `_item`,
* a merkle branch, and the index of `_item` in the tree.
* @param _item Merkle leaf
* @param _branch Merkle proof
* @param _index Index of `_item` in tree
* @return _current Calculated merkle root
**/
function branchRoot(
bytes32 _item,
bytes32[TREE_DEPTH] memory _branch,
uint256 _index
) internal pure returns (bytes32 _current) {
assembly {
_current := _item
let BRANCH_DATA_OFFSET := _branch
let f
f := shl(5, and(_index, 1))
mstore(f, _current)
mstore(sub(0x20, f), mload(BRANCH_DATA_OFFSET))
_current := keccak256(0, 0x40)
f := shl(5, iszero(and(_index, shl(1, 1))))
mstore(sub(0x20, f), _current)
mstore(f, mload(add(BRANCH_DATA_OFFSET, shl(5, 1))))
_current := keccak256(0, 0x40)
f := shl(5, iszero(and(_index, shl(2, 1))))
mstore(sub(0x20, f), _current)
mstore(f, mload(add(BRANCH_DATA_OFFSET, shl(5, 2))))
_current := keccak256(0, 0x40)
f := shl(5, iszero(and(_index, shl(3, 1))))
mstore(sub(0x20, f), _current)
mstore(f, mload(add(BRANCH_DATA_OFFSET, shl(5, 3))))
_current := keccak256(0, 0x40)
f := shl(5, iszero(and(_index, shl(4, 1))))
mstore(sub(0x20, f), _current)
mstore(f, mload(add(BRANCH_DATA_OFFSET, shl(5, 4))))
_current := keccak256(0, 0x40)
f := shl(5, iszero(and(_index, shl(5, 1))))
mstore(sub(0x20, f), _current)
mstore(f, mload(add(BRANCH_DATA_OFFSET, shl(5, 5))))
_current := keccak256(0, 0x40)
f := shl(5, iszero(and(_index, shl(6, 1))))
mstore(sub(0x20, f), _current)
mstore(f, mload(add(BRANCH_DATA_OFFSET, shl(5, 6))))
_current := keccak256(0, 0x40)
f := shl(5, iszero(and(_index, shl(7, 1))))
mstore(sub(0x20, f), _current)
mstore(f, mload(add(BRANCH_DATA_OFFSET, shl(5, 7))))
_current := keccak256(0, 0x40)
f := shl(5, iszero(and(_index, shl(8, 1))))
mstore(sub(0x20, f), _current)
mstore(f, mload(add(BRANCH_DATA_OFFSET, shl(5, 8))))
_current := keccak256(0, 0x40)
f := shl(5, iszero(and(_index, shl(9, 1))))
mstore(sub(0x20, f), _current)
mstore(f, mload(add(BRANCH_DATA_OFFSET, shl(5, 9))))
_current := keccak256(0, 0x40)
f := shl(5, iszero(and(_index, shl(10, 1))))
mstore(sub(0x20, f), _current)
mstore(f, mload(add(BRANCH_DATA_OFFSET, shl(5, 10))))
_current := keccak256(0, 0x40)
f := shl(5, iszero(and(_index, shl(11, 1))))
mstore(sub(0x20, f), _current)
mstore(f, mload(add(BRANCH_DATA_OFFSET, shl(5, 11))))
_current := keccak256(0, 0x40)
f := shl(5, iszero(and(_index, shl(12, 1))))
mstore(sub(0x20, f), _current)
mstore(f, mload(add(BRANCH_DATA_OFFSET, shl(5, 12))))
_current := keccak256(0, 0x40)
f := shl(5, iszero(and(_index, shl(13, 1))))
mstore(sub(0x20, f), _current)
mstore(f, mload(add(BRANCH_DATA_OFFSET, shl(5, 13))))
_current := keccak256(0, 0x40)
f := shl(5, iszero(and(_index, shl(14, 1))))
mstore(sub(0x20, f), _current)
mstore(f, mload(add(BRANCH_DATA_OFFSET, shl(5, 14))))
_current := keccak256(0, 0x40)
f := shl(5, iszero(and(_index, shl(15, 1))))
mstore(sub(0x20, f), _current)
mstore(f, mload(add(BRANCH_DATA_OFFSET, shl(5, 15))))
_current := keccak256(0, 0x40)
f := shl(5, iszero(and(_index, shl(16, 1))))
mstore(sub(0x20, f), _current)
mstore(f, mload(add(BRANCH_DATA_OFFSET, shl(5, 16))))
_current := keccak256(0, 0x40)
f := shl(5, iszero(and(_index, shl(17, 1))))
mstore(sub(0x20, f), _current)
mstore(f, mload(add(BRANCH_DATA_OFFSET, shl(5, 17))))
_current := keccak256(0, 0x40)
f := shl(5, iszero(and(_index, shl(18, 1))))
mstore(sub(0x20, f), _current)
mstore(f, mload(add(BRANCH_DATA_OFFSET, shl(5, 18))))
_current := keccak256(0, 0x40)
f := shl(5, iszero(and(_index, shl(19, 1))))
mstore(sub(0x20, f), _current)
mstore(f, mload(add(BRANCH_DATA_OFFSET, shl(5, 19))))
_current := keccak256(0, 0x40)
f := shl(5, iszero(and(_index, shl(20, 1))))
mstore(sub(0x20, f), _current)
mstore(f, mload(add(BRANCH_DATA_OFFSET, shl(5, 20))))
_current := keccak256(0, 0x40)
f := shl(5, iszero(and(_index, shl(21, 1))))
mstore(sub(0x20, f), _current)
mstore(f, mload(add(BRANCH_DATA_OFFSET, shl(5, 21))))
_current := keccak256(0, 0x40)
f := shl(5, iszero(and(_index, shl(22, 1))))
mstore(sub(0x20, f), _current)
mstore(f, mload(add(BRANCH_DATA_OFFSET, shl(5, 22))))
_current := keccak256(0, 0x40)
f := shl(5, iszero(and(_index, shl(23, 1))))
mstore(sub(0x20, f), _current)
mstore(f, mload(add(BRANCH_DATA_OFFSET, shl(5, 23))))
_current := keccak256(0, 0x40)
f := shl(5, iszero(and(_index, shl(24, 1))))
mstore(sub(0x20, f), _current)
mstore(f, mload(add(BRANCH_DATA_OFFSET, shl(5, 24))))
_current := keccak256(0, 0x40)
f := shl(5, iszero(and(_index, shl(25, 1))))
mstore(sub(0x20, f), _current)
mstore(f, mload(add(BRANCH_DATA_OFFSET, shl(5, 25))))
_current := keccak256(0, 0x40)
f := shl(5, iszero(and(_index, shl(26, 1))))
mstore(sub(0x20, f), _current)
mstore(f, mload(add(BRANCH_DATA_OFFSET, shl(5, 26))))
_current := keccak256(0, 0x40)
f := shl(5, iszero(and(_index, shl(27, 1))))
mstore(sub(0x20, f), _current)
mstore(f, mload(add(BRANCH_DATA_OFFSET, shl(5, 27))))
_current := keccak256(0, 0x40)
f := shl(5, iszero(and(_index, shl(28, 1))))
mstore(sub(0x20, f), _current)
mstore(f, mload(add(BRANCH_DATA_OFFSET, shl(5, 28))))
_current := keccak256(0, 0x40)
f := shl(5, iszero(and(_index, shl(29, 1))))
mstore(sub(0x20, f), _current)
mstore(f, mload(add(BRANCH_DATA_OFFSET, shl(5, 29))))
_current := keccak256(0, 0x40)
f := shl(5, iszero(and(_index, shl(30, 1))))
mstore(sub(0x20, f), _current)
mstore(f, mload(add(BRANCH_DATA_OFFSET, shl(5, 30))))
_current := keccak256(0, 0x40)
f := shl(5, iszero(and(_index, shl(31, 1))))
mstore(sub(0x20, f), _current)
mstore(f, mload(add(BRANCH_DATA_OFFSET, shl(5, 31))))
_current := keccak256(0, 0x40)
}
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.17;
import {IProposedOwnable} from "./interfaces/IProposedOwnable.sol";
/**
* @title ProposedOwnable
* @notice 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 via a two step process:
* 1. Call `proposeOwner`
* 2. Wait out the delay period
* 3. Call `acceptOwner`
*
* @dev 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.
*
* @dev The majority of this code was taken from the openzeppelin Ownable
* contract
*
*/
abstract contract ProposedOwnable is IProposedOwnable {
// ========== Custom Errors ===========
error ProposedOwnable__onlyOwner_notOwner();
error ProposedOwnable__onlyProposed_notProposedOwner();
error ProposedOwnable__ownershipDelayElapsed_delayNotElapsed();
error ProposedOwnable__proposeNewOwner_invalidProposal();
error ProposedOwnable__proposeNewOwner_noOwnershipChange();
error ProposedOwnable__renounceOwnership_noProposal();
error ProposedOwnable__renounceOwnership_invalidProposal();
// ============ Properties ============
address private _owner;
address private _proposed;
uint256 private _proposedOwnershipTimestamp;
uint256 private constant _delay = 7 days;
// ======== Getters =========
/**
* @notice Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @notice Returns the address of the proposed owner.
*/
function proposed() public view virtual returns (address) {
return _proposed;
}
/**
* @notice Returns the address of the proposed owner.
*/
function proposedTimestamp() public view virtual returns (uint256) {
return _proposedOwnershipTimestamp;
}
/**
* @notice Returns the delay period before a new owner can be accepted.
*/
function delay() public view virtual returns (uint256) {
return _delay;
}
/**
* @notice Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
if (_owner != msg.sender) revert ProposedOwnable__onlyOwner_notOwner();
_;
}
/**
* @notice Throws if called by any account other than the proposed owner.
*/
modifier onlyProposed() {
if (_proposed != msg.sender) revert ProposedOwnable__onlyProposed_notProposedOwner();
_;
}
/**
* @notice Throws if the ownership delay has not elapsed
*/
modifier ownershipDelayElapsed() {
// Ensure delay has elapsed
if ((block.timestamp - _proposedOwnershipTimestamp) <= _delay)
revert ProposedOwnable__ownershipDelayElapsed_delayNotElapsed();
_;
}
/**
* @notice Indicates if the ownership has been renounced() by
* checking if current owner is address(0)
*/
function renounced() public view returns (bool) {
return _owner == address(0);
}
// ======== External =========
/**
* @notice Sets the timestamp for an owner to be proposed, and sets the
* newly proposed owner as step 1 in a 2-step process
*/
function proposeNewOwner(address newlyProposed) public virtual onlyOwner {
// Contract as source of truth
if (_proposed == newlyProposed && _proposedOwnershipTimestamp != 0)
revert ProposedOwnable__proposeNewOwner_invalidProposal();
// Sanity check: reasonable proposal
if (_owner == newlyProposed) revert ProposedOwnable__proposeNewOwner_noOwnershipChange();
_setProposed(newlyProposed);
}
/**
* @notice Renounces ownership of the contract after a delay
*/
function renounceOwnership() public virtual onlyOwner ownershipDelayElapsed {
// Ensure there has been a proposal cycle started
if (_proposedOwnershipTimestamp == 0) revert ProposedOwnable__renounceOwnership_noProposal();
// Require proposed is set to 0
if (_proposed != address(0)) revert ProposedOwnable__renounceOwnership_invalidProposal();
// Emit event, set new owner, reset timestamp
_setOwner(address(0));
}
/**
* @notice Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function acceptProposedOwner() public virtual onlyProposed ownershipDelayElapsed {
// NOTE: no need to check if _owner == _proposed, because the _proposed
// is 0-d out and this check is implicitly enforced by modifier
// NOTE: no need to check if _proposedOwnershipTimestamp > 0 because
// the only time this would happen is if the _proposed was never
// set (will fail from modifier) or if the owner == _proposed (checked
// above)
// Emit event, set new owner, reset timestamp
_setOwner(_proposed);
}
// ======== Internal =========
function _setOwner(address newOwner) internal {
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
delete _proposedOwnershipTimestamp;
delete _proposed;
}
function _setProposed(address newlyProposed) private {
_proposedOwnershipTimestamp = block.timestamp;
_proposed = newlyProposed;
emit OwnershipProposed(newlyProposed);
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.17;
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import {ProposedOwnable} from "./ProposedOwnable.sol";
abstract contract ProposedOwnableUpgradeable is Initializable, ProposedOwnable {
/**
* @dev Initializes the contract setting the deployer as the initial
*/
function __ProposedOwnable_init() internal onlyInitializing {
__ProposedOwnable_init_unchained();
}
function __ProposedOwnable_init_unchained() internal onlyInitializing {
_setOwner(msg.sender);
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[47] private __GAP;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
/**
* @title IProposedOwnable
* @notice Defines a minimal interface for ownership with a two step proposal and acceptance
* process
*/
interface IProposedOwnable {
/**
* @dev This emits when change in ownership of a contract is proposed.
*/
event OwnershipProposed(address indexed proposedOwner);
/**
* @dev This emits when ownership of a contract changes.
*/
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @notice Get the address of the owner
* @return owner_ The address of the owner.
*/
function owner() external view returns (address owner_);
/**
* @notice Get the address of the proposed owner
* @return proposed_ The address of the proposed.
*/
function proposed() external view returns (address proposed_);
/**
* @notice Set the address of the proposed owner of the contract
* @param newlyProposed The proposed new owner of the contract
*/
function proposeNewOwner(address newlyProposed) external;
/**
* @notice Set the address of the proposed owner of the contract
*/
function acceptProposedOwner() external;
}{
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": [],
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"name":"MerkleLib__insert_treeIsFull","type":"error"},{"inputs":[],"name":"MerkleTreeManager__setArborist_alreadyArborist","type":"error"},{"inputs":[],"name":"MerkleTreeManager__setArborist_zeroAddress","type":"error"},{"inputs":[],"name":"ProposedOwnable__onlyOwner_notOwner","type":"error"},{"inputs":[],"name":"ProposedOwnable__onlyProposed_notProposedOwner","type":"error"},{"inputs":[],"name":"ProposedOwnable__ownershipDelayElapsed_delayNotElapsed","type":"error"},{"inputs":[],"name":"ProposedOwnable__proposeNewOwner_invalidProposal","type":"error"},{"inputs":[],"name":"ProposedOwnable__proposeNewOwner_noOwnershipChange","type":"error"},{"inputs":[],"name":"ProposedOwnable__renounceOwnership_invalidProposal","type":"error"},{"inputs":[],"name":"ProposedOwnable__renounceOwnership_noProposal","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previous","type":"address"},{"indexed":false,"internalType":"address","name":"updated","type":"address"}],"name":"ArboristUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"root","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"count","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"leaf","type":"bytes32"}],"name":"LeafInserted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"root","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"count","type":"uint256"},{"indexed":false,"internalType":"bytes32[]","name":"leaves","type":"bytes32[]"}],"name":"LeavesInserted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"proposedOwner","type":"address"}],"name":"OwnershipProposed","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"},{"inputs":[],"name":"acceptProposedOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"arborist","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"branch","outputs":[{"internalType":"bytes32[32]","name":"","type":"bytes32[32]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"count","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"delay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_arborist","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"leaf","type":"bytes32"}],"name":"insert","outputs":[{"internalType":"bytes32","name":"_root","type":"bytes32"},{"internalType":"uint256","name":"_count","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"leaves","type":"bytes32[]"}],"name":"insert","outputs":[{"internalType":"bytes32","name":"_root","type":"bytes32"},{"internalType":"uint256","name":"_count","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newlyProposed","type":"address"}],"name":"proposeNewOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"proposed","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proposedTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounced","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"root","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rootAndCount","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newArborist","type":"address"}],"name":"setArborist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"tree","outputs":[{"internalType":"uint256","name":"count","type":"uint256"}],"stateMutability":"view","type":"function"}]Contract Creation Code
608060405234801561001057600080fd5b506122f2806100206000396000f3fe608060405234801561001057600080fd5b50600436106101165760003560e01c80638da5cb5b116100a2578063c9b0a6de11610071578063c9b0a6de14610220578063d1851c9214610228578063d232c22014610239578063ebf0c71714610262578063fd54b2281461026a57600080fd5b80638da5cb5b146101db578063b1f8100d146101f2578063c4d66de814610205578063c5b350df1461021857600080fd5b806334a55ee6116100e957806334a55ee61461019a5780633cf52ffb146101ad5780634b72d0d4146101b55780636a42b8f8146101ca578063715018a6146101d357600080fd5b806306661abd1461011b5780631b373a98146101325780632d287e431461014757806331d0913c1461016f575b600080fd5b6052545b6040519081526020015b60405180910390f35b610145610140366004611f81565b610274565b005b61015a610155366004611fb1565b610362565b60408051928352602083019190915201610129565b605354610182906001600160a01b031681565b6040516001600160a01b039091168152602001610129565b61015a6101a8366004611fe0565b610473565b60025461011f565b6101bd6105ba565b604051610129919061209e565b62093a8061011f565b6101456105f6565b6000546201000090046001600160a01b0316610182565b610145610200366004611f81565b610629565b610145610213366004611f81565b6106d6565b6101456107f1565b61015a610861565b6001546001600160a01b0316610182565b6102526000546201000090046001600160a01b03161590565b6040519015158152602001610129565b61011f61087a565b60525461011f9081565b6000546201000090046001600160a01b031633146102a5576040516311a8a1bb60e31b815260040160405180910390fd5b6001600160a01b0381166102cc57604051630c11a52d60e11b815260040160405180910390fd5b6053546001600160a01b0390811690821681036102fc5760405163606e957b60e11b815260040160405180910390fd5b604080516001600160a01b038084168252841660208201527ff2fa31e21376edb31995720340ba00a41a12a7c8744a9bde552660121f4b7771910160405180910390a150605380546001600160a01b0319166001600160a01b0392909216919091179055565b60535460009081906001600160a01b031633146103b25760405162461bcd60e51b815260206004820152600960248201526808585c989bdc9a5cdd60ba1b60448201526064015b60405180910390fd5b60408051610440810180835261040092869291603291839190820190839060209082845b8154815260200190600101908083116103d65750505091835250506020918201549101529061088b565b80516032906104129082906020611eef565b506020918201519101555060525461042a6032610997565b60408051828152602081018490529081018590529092507fd50e83984b64a106ac2ee6314d689ec4d2a656d5ece6d94c585796944b52240c9060600160405180910390a1915091565b60535460009081906001600160a01b031633146104be5760405162461bcd60e51b815260206004820152600960248201526808585c989bdc9a5cdd60ba1b60448201526064016103a9565b6040805161044081018083526000926032918391820190839060209082845b8154815260200190600101908083116104dd575050509183525050602091820154910152845190915060005b818110156105475761053d868281518110610526576105266120d4565b60200260200101518461088b90919063ffffffff16565b9250600101610509565b508151829060329061055c9082906020611eef565b506020918201519082015582015192506105766032610997565b93507f3ef8438c07c6b4b67e70eace906a07e9b294c2f0066803f58e705567e1aa4f1b8484876040516105ab939291906120ea565b60405180910390a15050915091565b6105c2611f2d565b604080516104008101918290529060329060209082845b8154815260200190600101908083116105d9575050505050905090565b6000546201000090046001600160a01b03163314610627576040516311a8a1bb60e31b815260040160405180910390fd5b565b6000546201000090046001600160a01b0316331461065a576040516311a8a1bb60e31b815260040160405180910390fd5b6001546001600160a01b038281169116148015610678575060025415155b15610696576040516311bc066560e11b815260040160405180910390fd5b6000546001600160a01b038083166201000090920416036106ca57604051634a2fb73f60e11b815260040160405180910390fd5b6106d381611d4d565b50565b600054610100900460ff16158080156106f65750600054600160ff909116105b806107105750303b158015610710575060005460ff166001145b6107735760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016103a9565b6000805460ff191660011790558015610796576000805461ff0019166101001790555b61079f82611d9b565b6107a7611dcb565b80156107ed576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b6001546001600160a01b0316331461081c576040516311a7f27160e11b815260040160405180910390fd5b62093a806002544261082e9190612155565b1161084c576040516324e0285f60e21b815260040160405180910390fd5b600154610627906001600160a01b0316611dfa565b60008061086e6032610997565b60525490939092509050565b60006108866032610997565b905090565b610893611f4c565b60008360200180516108a490612168565b90819052905060016108b860206002612265565b6108c29190612155565b8111156108e257604051638eab04bb60e01b815260040160405180910390fd5b60005b6020811015610977578160011660010361091e5784518490826020811061090e5761090e6120d4565b6020020152508391506109919050565b84518160208110610931576109316120d4565b602002015184604051602001610951929190918252602082015260400190565b60408051601f1981840301815291905280516020909101209350600191821c91016108e5565b50604051638eab04bb60e01b815260040160405180910390fd5b92915050565b60208101546000908082036109ce57507f27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d75792915050565b60008360018316156109f05780546000526000602052604060002093506112a3565b6002831615610a355760018101546000527fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb560205260406000209350600191506112a3565b6004831615610a7a5760028101546000527fb4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d3060205260406000209350600291506112a3565b6008831615610abf5760038101546000527f21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba8560205260406000209350600391506112a3565b6010831615610b045760048101546000527fe58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a1934460205260406000209350600491506112a3565b6020831615610b495760058101546000527f0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d60205260406000209350600591506112a3565b6040831615610b8e5760068101546000527f887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a196860205260406000209350600691506112a3565b6080831615610bd35760078101546000527fffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f8360205260406000209350600791506112a3565b610100831615610c195760088101546000527f9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af60205260406000209350600891506112a3565b610200831615610c5f5760098101546000527fcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e060205260406000209350600991506112a3565b610400831615610ca557600a8101546000527ff9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a560205260406000209350600a91506112a3565b610800831615610ceb57600b8101546000527ff8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf89260205260406000209350600b91506112a3565b611000831615610d3157600c8101546000527f3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c60205260406000209350600c91506112a3565b612000831615610d7757600d8101546000527fc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb60205260406000209350600d91506112a3565b614000831615610dbd57600e8101546000527f5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc60205260406000209350600e91506112a3565b618000831615610e0357600f8101546000527fda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d260205260406000209350600f91506112a3565b62010000831615610e4a5760108101546000527f2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f60205260406000209350601091506112a3565b62020000831615610e915760118101546000527fe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a60205260406000209350601191506112a3565b62040000831615610ed85760128101546000527f5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a060205260406000209350601291506112a3565b62080000831615610f1f5760138101546000527fb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa060205260406000209350601391506112a3565b62100000831615610f665760148101546000527fc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e260205260406000209350601491506112a3565b62200000831615610fad5760158101546000527ff4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd960205260406000209350601591506112a3565b62400000831615610ff45760168101546000527f5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e37760205260406000209350601691506112a3565b6280000083161561103b5760178101546000527f4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee65260205260406000209350601791506112a3565b63010000008316156110835760188101546000527fcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef60205260406000209350601891506112a3565b63020000008316156110cb5760198101546000527f0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d60205260406000209350601991506112a3565b630400000083161561111357601a8101546000527fb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d060205260406000209350601a91506112a3565b630800000083161561115b57601b8101546000527f838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e60205260406000209350601b91506112a3565b63100000008316156111a357601c8101546000527f662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e60205260406000209350601c91506112a3565b63200000008316156111eb57601d8101546000527f388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea32260205260406000209350601d91506112a3565b634000000083161561123357601e8101546000527f93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d73560205260406000209350601e91506112a3565b638000000083161561127b57601f8101546000527f8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a960205260406000209350601f91506112a3565b7f27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d7579350602091505b601e8211611d45576001821015611301576002831680156112cf576001820154600052846020526112f8565b846000527fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb56020525b50604060002093505b6002821015611357576004831680156113255760028201546000528460205261134e565b846000527fb4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d306020525b50604060002093505b60038210156113ad5760088316801561137b576003820154600052846020526113a4565b846000527f21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba856020525b50604060002093505b6004821015611403576010831680156113d1576004820154600052846020526113fa565b846000527fe58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a193446020525b50604060002093505b60058210156114595760208316801561142757600582015460005284602052611450565b846000527f0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d6020525b50604060002093505b60068210156114af5760408316801561147d576006820154600052846020526114a6565b846000527f887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a19686020525b50604060002093505b6007821015611505576080831680156114d3576007820154600052846020526114fc565b846000527fffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f836020525b50604060002093505b600882101561155c576101008316801561152a57600882015460005284602052611553565b846000527f9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af6020525b50604060002093505b60098210156115b35761020083168015611581576009820154600052846020526115aa565b846000527fcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e06020525b50604060002093505b600a82101561160a57610400831680156115d857600a82015460005284602052611601565b846000527ff9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a56020525b50604060002093505b600b821015611661576108008316801561162f57600b82015460005284602052611658565b846000527ff8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf8926020525b50604060002093505b600c8210156116b8576110008316801561168657600c820154600052846020526116af565b846000527f3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c6020525b50604060002093505b600d82101561170f57612000831680156116dd57600d82015460005284602052611706565b846000527fc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb6020525b50604060002093505b600e821015611766576140008316801561173457600e8201546000528460205261175d565b846000527f5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc6020525b50604060002093505b600f8210156117bd576180008316801561178b57600f820154600052846020526117b4565b846000527fda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d26020525b50604060002093505b60108210156118155762010000831680156117e35760108201546000528460205261180c565b846000527f2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f6020525b50604060002093505b601182101561186d57620200008316801561183b57601182015460005284602052611864565b846000527fe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a6020525b50604060002093505b60128210156118c5576204000083168015611893576012820154600052846020526118bc565b846000527f5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a06020525b50604060002093505b601382101561191d5762080000831680156118eb57601382015460005284602052611914565b846000527fb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa06020525b50604060002093505b60148210156119755762100000831680156119435760148201546000528460205261196c565b846000527fc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e26020525b50604060002093505b60158210156119cd57622000008316801561199b576015820154600052846020526119c4565b846000527ff4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd96020525b50604060002093505b6016821015611a255762400000831680156119f357601682015460005284602052611a1c565b846000527f5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e3776020525b50604060002093505b6017821015611a7d576280000083168015611a4b57601782015460005284602052611a74565b846000527f4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee6526020525b50604060002093505b6018821015611ad657630100000083168015611aa457601882015460005284602052611acd565b846000527fcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef6020525b50604060002093505b6019821015611b2f57630200000083168015611afd57601982015460005284602052611b26565b846000527f0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d6020525b50604060002093505b601a821015611b8857630400000083168015611b5657601a82015460005284602052611b7f565b846000527fb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d06020525b50604060002093505b601b821015611be157630800000083168015611baf57601b82015460005284602052611bd8565b846000527f838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e6020525b50604060002093505b601c821015611c3a57631000000083168015611c0857601c82015460005284602052611c31565b846000527f662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e6020525b50604060002093505b601d821015611c9357632000000083168015611c6157601d82015460005284602052611c8a565b846000527f388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea3226020525b50604060002093505b601e821015611cec57634000000083168015611cba57601e82015460005284602052611ce3565b846000527f93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d7356020525b50604060002093505b601f821015611d4557638000000083168015611d1357601f82015460005284602052611d3c565b846000527f8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a96020525b50604060002093505b505050919050565b42600255600180546001600160a01b0319166001600160a01b0383169081179091556040517f6ab4d119f23076e8ad491bc65ce85f017fb0591dce08755ba8591059cc51737a90600090a250565b600054610100900460ff16611dc25760405162461bcd60e51b81526004016103a990612271565b6106d381611e76565b600054610100900460ff16611df25760405162461bcd60e51b81526004016103a990612271565b610627611ebf565b600080546040516001600160a01b03808516936201000090930416917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b03909216620100000262010000600160b01b0319909216919091178155600255600180546001600160a01b0319169055565b600054610100900460ff16611e9d5760405162461bcd60e51b81526004016103a990612271565b605380546001600160a01b0319166001600160a01b0392909216919091179055565b600054610100900460ff16611ee65760405162461bcd60e51b81526004016103a990612271565b61062733611dfa565b8260208101928215611f1d579160200282015b82811115611f1d578251825591602001919060010190611f02565b50611f29929150611f6c565b5090565b6040518061040001604052806020906020820280368337509192915050565b6040518060400160405280611f5f611f2d565b8152602001600081525090565b5b80821115611f295760008155600101611f6d565b600060208284031215611f9357600080fd5b81356001600160a01b0381168114611faa57600080fd5b9392505050565b600060208284031215611fc357600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b60006020808385031215611ff357600080fd5b823567ffffffffffffffff8082111561200b57600080fd5b818501915085601f83011261201f57600080fd5b81358181111561203157612031611fca565b8060051b604051601f19603f8301168101818110858211171561205657612056611fca565b60405291825284820192508381018501918883111561207457600080fd5b938501935b8285101561209257843584529385019392850192612079565b98975050505050505050565b6104008101818360005b60208082106120b757506120cb565b8251845292830192909101906001016120a8565b50505092915050565b634e487b7160e01b600052603260045260246000fd5b6000606082018583526020858185015260606040850152818551808452608086019150828701935060005b8181101561213157845183529383019391830191600101612115565b509098975050505050505050565b634e487b7160e01b600052601160045260246000fd5b818103818111156109915761099161213f565b60006001820161217a5761217a61213f565b5060010190565b600181815b808511156121bc5781600019048211156121a2576121a261213f565b808516156121af57918102915b93841c9390800290612186565b509250929050565b6000826121d357506001610991565b816121e057506000610991565b81600181146121f657600281146122005761221c565b6001915050610991565b60ff8411156122115761221161213f565b50506001821b610991565b5060208310610133831016604e8410600b841016171561223f575081810a610991565b6122498383612181565b806000190482111561225d5761225d61213f565b029392505050565b6000611faa83836121c4565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b60608201526080019056fea2646970667358221220692efb4fde2ef60f8a670bcf66710807eef1fc4f3543297bb32ad63f5a4f336564736f6c63430008110033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101165760003560e01c80638da5cb5b116100a2578063c9b0a6de11610071578063c9b0a6de14610220578063d1851c9214610228578063d232c22014610239578063ebf0c71714610262578063fd54b2281461026a57600080fd5b80638da5cb5b146101db578063b1f8100d146101f2578063c4d66de814610205578063c5b350df1461021857600080fd5b806334a55ee6116100e957806334a55ee61461019a5780633cf52ffb146101ad5780634b72d0d4146101b55780636a42b8f8146101ca578063715018a6146101d357600080fd5b806306661abd1461011b5780631b373a98146101325780632d287e431461014757806331d0913c1461016f575b600080fd5b6052545b6040519081526020015b60405180910390f35b610145610140366004611f81565b610274565b005b61015a610155366004611fb1565b610362565b60408051928352602083019190915201610129565b605354610182906001600160a01b031681565b6040516001600160a01b039091168152602001610129565b61015a6101a8366004611fe0565b610473565b60025461011f565b6101bd6105ba565b604051610129919061209e565b62093a8061011f565b6101456105f6565b6000546201000090046001600160a01b0316610182565b610145610200366004611f81565b610629565b610145610213366004611f81565b6106d6565b6101456107f1565b61015a610861565b6001546001600160a01b0316610182565b6102526000546201000090046001600160a01b03161590565b6040519015158152602001610129565b61011f61087a565b60525461011f9081565b6000546201000090046001600160a01b031633146102a5576040516311a8a1bb60e31b815260040160405180910390fd5b6001600160a01b0381166102cc57604051630c11a52d60e11b815260040160405180910390fd5b6053546001600160a01b0390811690821681036102fc5760405163606e957b60e11b815260040160405180910390fd5b604080516001600160a01b038084168252841660208201527ff2fa31e21376edb31995720340ba00a41a12a7c8744a9bde552660121f4b7771910160405180910390a150605380546001600160a01b0319166001600160a01b0392909216919091179055565b60535460009081906001600160a01b031633146103b25760405162461bcd60e51b815260206004820152600960248201526808585c989bdc9a5cdd60ba1b60448201526064015b60405180910390fd5b60408051610440810180835261040092869291603291839190820190839060209082845b8154815260200190600101908083116103d65750505091835250506020918201549101529061088b565b80516032906104129082906020611eef565b506020918201519101555060525461042a6032610997565b60408051828152602081018490529081018590529092507fd50e83984b64a106ac2ee6314d689ec4d2a656d5ece6d94c585796944b52240c9060600160405180910390a1915091565b60535460009081906001600160a01b031633146104be5760405162461bcd60e51b815260206004820152600960248201526808585c989bdc9a5cdd60ba1b60448201526064016103a9565b6040805161044081018083526000926032918391820190839060209082845b8154815260200190600101908083116104dd575050509183525050602091820154910152845190915060005b818110156105475761053d868281518110610526576105266120d4565b60200260200101518461088b90919063ffffffff16565b9250600101610509565b508151829060329061055c9082906020611eef565b506020918201519082015582015192506105766032610997565b93507f3ef8438c07c6b4b67e70eace906a07e9b294c2f0066803f58e705567e1aa4f1b8484876040516105ab939291906120ea565b60405180910390a15050915091565b6105c2611f2d565b604080516104008101918290529060329060209082845b8154815260200190600101908083116105d9575050505050905090565b6000546201000090046001600160a01b03163314610627576040516311a8a1bb60e31b815260040160405180910390fd5b565b6000546201000090046001600160a01b0316331461065a576040516311a8a1bb60e31b815260040160405180910390fd5b6001546001600160a01b038281169116148015610678575060025415155b15610696576040516311bc066560e11b815260040160405180910390fd5b6000546001600160a01b038083166201000090920416036106ca57604051634a2fb73f60e11b815260040160405180910390fd5b6106d381611d4d565b50565b600054610100900460ff16158080156106f65750600054600160ff909116105b806107105750303b158015610710575060005460ff166001145b6107735760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016103a9565b6000805460ff191660011790558015610796576000805461ff0019166101001790555b61079f82611d9b565b6107a7611dcb565b80156107ed576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b6001546001600160a01b0316331461081c576040516311a7f27160e11b815260040160405180910390fd5b62093a806002544261082e9190612155565b1161084c576040516324e0285f60e21b815260040160405180910390fd5b600154610627906001600160a01b0316611dfa565b60008061086e6032610997565b60525490939092509050565b60006108866032610997565b905090565b610893611f4c565b60008360200180516108a490612168565b90819052905060016108b860206002612265565b6108c29190612155565b8111156108e257604051638eab04bb60e01b815260040160405180910390fd5b60005b6020811015610977578160011660010361091e5784518490826020811061090e5761090e6120d4565b6020020152508391506109919050565b84518160208110610931576109316120d4565b602002015184604051602001610951929190918252602082015260400190565b60408051601f1981840301815291905280516020909101209350600191821c91016108e5565b50604051638eab04bb60e01b815260040160405180910390fd5b92915050565b60208101546000908082036109ce57507f27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d75792915050565b60008360018316156109f05780546000526000602052604060002093506112a3565b6002831615610a355760018101546000527fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb560205260406000209350600191506112a3565b6004831615610a7a5760028101546000527fb4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d3060205260406000209350600291506112a3565b6008831615610abf5760038101546000527f21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba8560205260406000209350600391506112a3565b6010831615610b045760048101546000527fe58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a1934460205260406000209350600491506112a3565b6020831615610b495760058101546000527f0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d60205260406000209350600591506112a3565b6040831615610b8e5760068101546000527f887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a196860205260406000209350600691506112a3565b6080831615610bd35760078101546000527fffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f8360205260406000209350600791506112a3565b610100831615610c195760088101546000527f9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af60205260406000209350600891506112a3565b610200831615610c5f5760098101546000527fcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e060205260406000209350600991506112a3565b610400831615610ca557600a8101546000527ff9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a560205260406000209350600a91506112a3565b610800831615610ceb57600b8101546000527ff8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf89260205260406000209350600b91506112a3565b611000831615610d3157600c8101546000527f3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c60205260406000209350600c91506112a3565b612000831615610d7757600d8101546000527fc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb60205260406000209350600d91506112a3565b614000831615610dbd57600e8101546000527f5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc60205260406000209350600e91506112a3565b618000831615610e0357600f8101546000527fda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d260205260406000209350600f91506112a3565b62010000831615610e4a5760108101546000527f2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f60205260406000209350601091506112a3565b62020000831615610e915760118101546000527fe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a60205260406000209350601191506112a3565b62040000831615610ed85760128101546000527f5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a060205260406000209350601291506112a3565b62080000831615610f1f5760138101546000527fb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa060205260406000209350601391506112a3565b62100000831615610f665760148101546000527fc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e260205260406000209350601491506112a3565b62200000831615610fad5760158101546000527ff4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd960205260406000209350601591506112a3565b62400000831615610ff45760168101546000527f5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e37760205260406000209350601691506112a3565b6280000083161561103b5760178101546000527f4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee65260205260406000209350601791506112a3565b63010000008316156110835760188101546000527fcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef60205260406000209350601891506112a3565b63020000008316156110cb5760198101546000527f0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d60205260406000209350601991506112a3565b630400000083161561111357601a8101546000527fb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d060205260406000209350601a91506112a3565b630800000083161561115b57601b8101546000527f838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e60205260406000209350601b91506112a3565b63100000008316156111a357601c8101546000527f662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e60205260406000209350601c91506112a3565b63200000008316156111eb57601d8101546000527f388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea32260205260406000209350601d91506112a3565b634000000083161561123357601e8101546000527f93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d73560205260406000209350601e91506112a3565b638000000083161561127b57601f8101546000527f8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a960205260406000209350601f91506112a3565b7f27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d7579350602091505b601e8211611d45576001821015611301576002831680156112cf576001820154600052846020526112f8565b846000527fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb56020525b50604060002093505b6002821015611357576004831680156113255760028201546000528460205261134e565b846000527fb4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d306020525b50604060002093505b60038210156113ad5760088316801561137b576003820154600052846020526113a4565b846000527f21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba856020525b50604060002093505b6004821015611403576010831680156113d1576004820154600052846020526113fa565b846000527fe58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a193446020525b50604060002093505b60058210156114595760208316801561142757600582015460005284602052611450565b846000527f0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d6020525b50604060002093505b60068210156114af5760408316801561147d576006820154600052846020526114a6565b846000527f887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a19686020525b50604060002093505b6007821015611505576080831680156114d3576007820154600052846020526114fc565b846000527fffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f836020525b50604060002093505b600882101561155c576101008316801561152a57600882015460005284602052611553565b846000527f9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af6020525b50604060002093505b60098210156115b35761020083168015611581576009820154600052846020526115aa565b846000527fcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e06020525b50604060002093505b600a82101561160a57610400831680156115d857600a82015460005284602052611601565b846000527ff9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a56020525b50604060002093505b600b821015611661576108008316801561162f57600b82015460005284602052611658565b846000527ff8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf8926020525b50604060002093505b600c8210156116b8576110008316801561168657600c820154600052846020526116af565b846000527f3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c6020525b50604060002093505b600d82101561170f57612000831680156116dd57600d82015460005284602052611706565b846000527fc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb6020525b50604060002093505b600e821015611766576140008316801561173457600e8201546000528460205261175d565b846000527f5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc6020525b50604060002093505b600f8210156117bd576180008316801561178b57600f820154600052846020526117b4565b846000527fda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d26020525b50604060002093505b60108210156118155762010000831680156117e35760108201546000528460205261180c565b846000527f2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f6020525b50604060002093505b601182101561186d57620200008316801561183b57601182015460005284602052611864565b846000527fe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a6020525b50604060002093505b60128210156118c5576204000083168015611893576012820154600052846020526118bc565b846000527f5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a06020525b50604060002093505b601382101561191d5762080000831680156118eb57601382015460005284602052611914565b846000527fb46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa06020525b50604060002093505b60148210156119755762100000831680156119435760148201546000528460205261196c565b846000527fc65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e26020525b50604060002093505b60158210156119cd57622000008316801561199b576015820154600052846020526119c4565b846000527ff4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd96020525b50604060002093505b6016821015611a255762400000831680156119f357601682015460005284602052611a1c565b846000527f5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e3776020525b50604060002093505b6017821015611a7d576280000083168015611a4b57601782015460005284602052611a74565b846000527f4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee6526020525b50604060002093505b6018821015611ad657630100000083168015611aa457601882015460005284602052611acd565b846000527fcdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef6020525b50604060002093505b6019821015611b2f57630200000083168015611afd57601982015460005284602052611b26565b846000527f0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d6020525b50604060002093505b601a821015611b8857630400000083168015611b5657601a82015460005284602052611b7f565b846000527fb8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d06020525b50604060002093505b601b821015611be157630800000083168015611baf57601b82015460005284602052611bd8565b846000527f838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e6020525b50604060002093505b601c821015611c3a57631000000083168015611c0857601c82015460005284602052611c31565b846000527f662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e6020525b50604060002093505b601d821015611c9357632000000083168015611c6157601d82015460005284602052611c8a565b846000527f388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea3226020525b50604060002093505b601e821015611cec57634000000083168015611cba57601e82015460005284602052611ce3565b846000527f93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d7356020525b50604060002093505b601f821015611d4557638000000083168015611d1357601f82015460005284602052611d3c565b846000527f8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a96020525b50604060002093505b505050919050565b42600255600180546001600160a01b0319166001600160a01b0383169081179091556040517f6ab4d119f23076e8ad491bc65ce85f017fb0591dce08755ba8591059cc51737a90600090a250565b600054610100900460ff16611dc25760405162461bcd60e51b81526004016103a990612271565b6106d381611e76565b600054610100900460ff16611df25760405162461bcd60e51b81526004016103a990612271565b610627611ebf565b600080546040516001600160a01b03808516936201000090930416917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b03909216620100000262010000600160b01b0319909216919091178155600255600180546001600160a01b0319169055565b600054610100900460ff16611e9d5760405162461bcd60e51b81526004016103a990612271565b605380546001600160a01b0319166001600160a01b0392909216919091179055565b600054610100900460ff16611ee65760405162461bcd60e51b81526004016103a990612271565b61062733611dfa565b8260208101928215611f1d579160200282015b82811115611f1d578251825591602001919060010190611f02565b50611f29929150611f6c565b5090565b6040518061040001604052806020906020820280368337509192915050565b6040518060400160405280611f5f611f2d565b8152602001600081525090565b5b80821115611f295760008155600101611f6d565b600060208284031215611f9357600080fd5b81356001600160a01b0381168114611faa57600080fd5b9392505050565b600060208284031215611fc357600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b60006020808385031215611ff357600080fd5b823567ffffffffffffffff8082111561200b57600080fd5b818501915085601f83011261201f57600080fd5b81358181111561203157612031611fca565b8060051b604051601f19603f8301168101818110858211171561205657612056611fca565b60405291825284820192508381018501918883111561207457600080fd5b938501935b8285101561209257843584529385019392850192612079565b98975050505050505050565b6104008101818360005b60208082106120b757506120cb565b8251845292830192909101906001016120a8565b50505092915050565b634e487b7160e01b600052603260045260246000fd5b6000606082018583526020858185015260606040850152818551808452608086019150828701935060005b8181101561213157845183529383019391830191600101612115565b509098975050505050505050565b634e487b7160e01b600052601160045260246000fd5b818103818111156109915761099161213f565b60006001820161217a5761217a61213f565b5060010190565b600181815b808511156121bc5781600019048211156121a2576121a261213f565b808516156121af57918102915b93841c9390800290612186565b509250929050565b6000826121d357506001610991565b816121e057506000610991565b81600181146121f657600281146122005761221c565b6001915050610991565b60ff8411156122115761221161213f565b50506001821b610991565b5060208310610133831016604e8410600b841016171561223f575081810a610991565b6122498383612181565b806000190482111561225d5761225d61213f565b029392505050565b6000611faa83836121c4565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b60608201526080019056fea2646970667358221220692efb4fde2ef60f8a670bcf66710807eef1fc4f3543297bb32ad63f5a4f336564736f6c63430008110033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
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.