Source Code
Latest 25 from a total of 144 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Update Merkle Ro... | 38217184 | 19 days ago | IN | 0 ETH | 0.00000021 | ||||
| Update Merkle Ro... | 37910921 | 26 days ago | IN | 0 ETH | 0.00000015 | ||||
| Update Merkle Ro... | 37823382 | 28 days ago | IN | 0 ETH | 0.00000094 | ||||
| Update Merkle Ro... | 37212954 | 42 days ago | IN | 0 ETH | 0.00000014 | ||||
| Update Merkle Ro... | 37122920 | 44 days ago | IN | 0 ETH | 0.00000017 | ||||
| Update Merkle Ro... | 36081643 | 68 days ago | IN | 0 ETH | 0.00000009 | ||||
| Update Merkle Ro... | 35341206 | 85 days ago | IN | 0 ETH | 0.00000026 | ||||
| Update Merkle Ro... | 35056859 | 92 days ago | IN | 0 ETH | 0.00000006 | ||||
| Update Merkle Ro... | 34927256 | 95 days ago | IN | 0 ETH | 0.00000005 | ||||
| Update Merkle Ro... | 34572095 | 103 days ago | IN | 0 ETH | 0.00000006 | ||||
| Update Merkle Ro... | 34269690 | 110 days ago | IN | 0 ETH | 0.00000007 | ||||
| Update Merkle Ro... | 34140087 | 113 days ago | IN | 0 ETH | 0.00000046 | ||||
| Update Merkle Ro... | 34010485 | 116 days ago | IN | 0 ETH | 0.00000013 | ||||
| Update Merkle Ro... | 33726384 | 123 days ago | IN | 0 ETH | 0.00000009 | ||||
| Update Merkle Ro... | 33683183 | 124 days ago | IN | 0 ETH | 0.00000026 | ||||
| Update Merkle Ro... | 33510847 | 128 days ago | IN | 0 ETH | 0.00000077 | ||||
| Update Merkle Ro... | 33086767 | 137 days ago | IN | 0 ETH | 0.00000014 | ||||
| Update Merkle Ro... | 32771529 | 145 days ago | IN | 0 ETH | 0.00000012 | ||||
| Update Merkle Ro... | 32698581 | 146 days ago | IN | 0 ETH | 0.0000005 | ||||
| Update Merkle Ro... | 32344297 | 155 days ago | IN | 0 ETH | 0.0000008 | ||||
| Update Merkle Ro... | 32159967 | 159 days ago | IN | 0 ETH | 0.00000008 | ||||
| Update Merkle Ro... | 32021130 | 162 days ago | IN | 0 ETH | 0.00000013 | ||||
| Update Merkle Ro... | 31977052 | 163 days ago | IN | 0 ETH | 0.00000008 | ||||
| Update Merkle Ro... | 31866108 | 166 days ago | IN | 0 ETH | 0.00000043 | ||||
| Update Merkle Ro... | 31822904 | 167 days ago | IN | 0 ETH | 0.0000002 |
Cross-Chain Transactions
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
AnteHashTreeIndexV2
Compiler Version
v0.8.23+commit.f704f362
Optimization Enabled:
Yes with 10000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0-only
// ┏━━━┓━━━━━┏┓━━━━━━━━━┏━━━┓━━━━━━━━━━━━━━━━━━━━━━━
// ┃┏━┓┃━━━━┏┛┗┓━━━━━━━━┃┏━━┛━━━━━━━━━━━━━━━━━━━━━━━
// ┃┗━┛┃┏━┓━┗┓┏┛┏━━┓━━━━┃┗━━┓┏┓┏━┓━┏━━┓━┏━┓━┏━━┓┏━━┓
// ┃┏━┓┃┃┏┓┓━┃┃━┃┏┓┃━━━━┃┏━━┛┣┫┃┏┓┓┗━┓┃━┃┏┓┓┃┏━┛┃┏┓┃
// ┃┃ ┃┃┃┃┃┃━┃┗┓┃┃━┫━┏┓━┃┃━━━┃┃┃┃┃┃┃┗┛┗┓┃┃┃┃┃┗━┓┃┃━┫
// ┗┛ ┗┛┗┛┗┛━┗━┛┗━━┛━┗┛━┗┛━━━┗┛┗┛┗┛┗━━━┛┗┛┗┛┗━━┛┗━━┛
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
pragma solidity 0.8.23;
import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { IAnteHashTreeIndexV2 } from "./interfaces/IAnteHashTreeIndexV2.sol";
import { MerklePatricia } from "./libraries/MerklePatricia.sol";
/// @title Ante Hash Tree Index V2 smart contract
/// @notice Contract that stores the merkle roots of committed Antes
contract AnteHashTreeIndexV2 is IAnteHashTreeIndexV2, Ownable {
using EnumerableSet for EnumerableSet.AddressSet;
/// @dev A set of unique relayer addresses that are allowed
/// to update the merkle root.
EnumerableSet.AddressSet private allowedRelayers;
/// @notice The latest Merkle root of this batch
bytes32 public latestMerkleRoot;
/// @notice Data URI for IPFS or Arweave which contains the source
/// data used for constructing the Merkle root
string public latestDataUri;
/// @notice Address of the relayer that submitted the latest batch
address public latestRelayer;
constructor(address initialOwner) Ownable(initialOwner) { }
/// @inheritdoc IAnteHashTreeIndexV2
function addRelayer(address _relayerAddr) external override onlyOwner {
bool success = allowedRelayers.add(_relayerAddr);
if (!success) {
revert AlreadyExists();
}
emit RelayerAddressAdded(_relayerAddr);
}
/// @inheritdoc IAnteHashTreeIndexV2
function removeRelayer(address _relayerAddr) external override onlyOwner {
bool success = allowedRelayers.remove(_relayerAddr);
if (!success) {
revert NotExists();
}
emit RelayerAddressRemoved(_relayerAddr);
}
/// @inheritdoc IAnteHashTreeIndexV2
function updateMerkleRoot(bytes32 root, string calldata dataUri) external {
if (!allowedRelayers.contains(msg.sender)) {
revert NotAllowed();
}
bytes32 prevRoot = latestMerkleRoot;
latestMerkleRoot = root;
latestDataUri = dataUri;
latestRelayer = msg.sender;
emit MerkleRootUpdated(msg.sender, prevRoot, root, dataUri);
}
/// @inheritdoc IAnteHashTreeIndexV2
function isRelayerAllowed(address _relayerAddr) external view override returns (bool) {
return allowedRelayers.contains(_relayerAddr);
}
/// @inheritdoc IAnteHashTreeIndexV2
function getAllowedRelayers() external view override returns (address[] memory) {
address[] memory allowedRelayerAddresses = new address[](allowedRelayers.length());
for (uint256 i = 0; i < allowedRelayers.length(); i++) {
allowedRelayerAddresses[i] = allowedRelayers.at(i);
}
return allowedRelayerAddresses;
}
/// @inheritdoc IAnteHashTreeIndexV2
function verifyMerkleProof(
bytes32 merkleRoot,
bytes[] memory merkleProof,
bytes memory hash
)
external
pure
returns (bool)
{
return MerklePatricia.verifyInclusionProof(merkleRoot, merkleProof, hash);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.20;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```solidity
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position is the index of the value in the `values` array plus 1.
// Position 0 is used to mean a value is not in the set.
mapping(bytes32 value => uint256) _positions;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._positions[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We cache the value's position to prevent multiple reads from the same storage slot
uint256 position = set._positions[value];
if (position != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 valueIndex = position - 1;
uint256 lastIndex = set._values.length - 1;
if (valueIndex != lastIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the lastValue to the index where the value to delete is
set._values[valueIndex] = lastValue;
// Update the tracked position of the lastValue (that was just moved)
set._positions[lastValue] = position;
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the tracked position for the deleted slot
delete set._positions[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._positions[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: GPL-3.0-only
// ┏━━━┓━━━━━┏┓━━━━━━━━━┏━━━┓━━━━━━━━━━━━━━━━━━━━━━━
// ┃┏━┓┃━━━━┏┛┗┓━━━━━━━━┃┏━━┛━━━━━━━━━━━━━━━━━━━━━━━
// ┃┗━┛┃┏━┓━┗┓┏┛┏━━┓━━━━┃┗━━┓┏┓┏━┓━┏━━┓━┏━┓━┏━━┓┏━━┓
// ┃┏━┓┃┃┏┓┓━┃┃━┃┏┓┃━━━━┃┏━━┛┣┫┃┏┓┓┗━┓┃━┃┏┓┓┃┏━┛┃┏┓┃
// ┃┃ ┃┃┃┃┃┃━┃┗┓┃┃━┫━┏┓━┃┃━━━┃┃┃┃┃┃┃┗┛┗┓┃┃┃┃┃┗━┓┃┃━┫
// ┗┛ ┗┛┗┛┗┛━┗━┛┗━━┛━┗┛━┗┛━━━┗┛┗┛┗┛┗━━━┛┗┛┗┛┗━━┛┗━━┛
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
pragma solidity 0.8.23;
/// @title Ante Hash Tree Index V2 smart contract
/// @notice Contract that stores the merkle roots of committed antes
interface IAnteHashTreeIndexV2 {
/// @notice Error thrown when entry already exists
error AlreadyExists();
/// @notice Error thrown when entry does not exist
error NotExists();
/// @notice Error thrown when caller is not allowed to perform the action
error NotAllowed();
/// @notice Emitted when a new merkle root is written to the contract
/// @param sender The address of the relayer that sent the update
/// @param previousRoot The merkle root before this update
/// @param newRoot The merkle root added to the ante hash tree index
/// @param dataUri The data URI for the new root
event MerkleRootUpdated(address indexed sender, bytes32 previousRoot, bytes32 newRoot, string dataUri);
/// @notice Emitted when a relayer address is added to the whitelist
/// @param relayerAddr The relayer address that was added
event RelayerAddressAdded(address indexed relayerAddr);
/// @notice Emitted when a relayer address is removed from the whitelist
/// @param relayerAddr The relayer address that was removed
event RelayerAddressRemoved(address indexed relayerAddr);
/// @notice Adds the provided relayer address to the whitelist
/// @param _relayerAddr The address of the relayer to add
function addRelayer(address _relayerAddr) external;
/// @notice Removes the provided relayer address from the whitelist
/// @param _relayerAddr The address of the relayer to remove
function removeRelayer(address _relayerAddr) external;
/// @notice Updates the latest stored root and data URI
/// @param root The new root of the Merkle Trie
/// @param dataUri The new data URI containing data used for generating
/// the Merkle Trie
function updateMerkleRoot(bytes32 root, string calldata dataUri) external;
/// @notice Check if the provided relayer address exists in the whitelist
/// @param _relayerAddr The address of the relayer to check
/// @return true if the provided address is in the whitelist
function isRelayerAllowed(address _relayerAddr) external view returns (bool);
/// @notice Retrieves an array of all allowed relayer addresses
/// @return A list of relayer addresses that are allowed to be update the merkle root
function getAllowedRelayers() external view returns (address[] memory);
/// @notice Verifies MPT merkle proof for a given key hash
/// @param merkleRoot hash of the merkle patricia trie
/// @param merkleProof list of proof nodes
/// @param hash hash of a key to verify
/// @return bool `true` if a given proof is valid for a given hash, `false` otherwise
function verifyMerkleProof(
bytes32 merkleRoot,
bytes[] memory merkleProof,
bytes memory hash
)
external
pure
returns (bool);
}// SPDX-License-Identifier: Apache2
pragma solidity 0.8.23;
import {
NodeKind,
NodeHandle,
Extension,
Branch,
NibbledBranch,
ValueOption,
NodeHandleOption,
Leaf,
TrieNode
} from "./trie/Node.sol";
import { Option } from "./trie/Option.sol";
import { NibbleSlice, NibbleSliceOps } from "./trie/NibbleSlice.sol";
import { TrieDB } from "./trie/TrieDB.sol";
import { EthereumTrieDB } from "./trie/ethereum/EthereumTrieDB.sol";
/**
* @title A Merkle Patricia library
* @author Polytope Labs
* @dev Use this library to verify merkle patricia inclusion proofs
*/
library MerklePatricia {
/// @notice libraries in solidity can only have constant variables
/// @dev MAX_TRIE_DEPTH, we don't explore deeply nested trie keys.
uint256 internal constant MAX_TRIE_DEPTH = 50;
/**
* @notice Verifies ethereum specific merkle patricia trie inclusion proofs as described by EIP-1186.
*
* @param root hash of the merkle patricia trie
* @param proof list of proof nodes
* @param key a key to verify
*
* @return bool `true` if a given proof is valid for a given key, `false` otherwise
*/
function verifyInclusionProof(bytes32 root, bytes[] memory proof, bytes memory key) internal pure returns (bool) {
TrieNode[] memory nodes = new TrieNode[](proof.length);
for (uint256 i = 0; i < proof.length; i++) {
nodes[i] = TrieNode(keccak256(proof[i]), proof[i]);
}
NibbleSlice memory keyNibbles = NibbleSlice(key, 0);
NodeKind memory node = EthereumTrieDB.decodeNodeKind(TrieDB.get(nodes, root));
// worst case scenario, so we avoid unbounded loops
for (uint256 j = 0; j < MAX_TRIE_DEPTH; j++) {
NodeHandle memory nextNode;
if (TrieDB.isLeaf(node)) {
Leaf memory leaf = EthereumTrieDB.decodeLeaf(node);
// Let's retrieve the offset to be used
uint256 offset = keyNibbles.offset % 2 == 0 ? keyNibbles.offset / 2 : keyNibbles.offset / 2 + 1;
// Let's cut the key passed as input
keyNibbles = NibbleSlice(NibbleSliceOps.bytesSlice(keyNibbles.data, offset), 0);
if (NibbleSliceOps.eq(leaf.key, keyNibbles)) {
return true;
}
break;
} else if (TrieDB.isExtension(node)) {
Extension memory extension = EthereumTrieDB.decodeExtension(node);
if (NibbleSliceOps.startsWith(keyNibbles, extension.key)) {
// Let's cut the key passed as input
keyNibbles =
NibbleSlice(NibbleSliceOps.bytesSlice(keyNibbles.data, NibbleSliceOps.len(extension.key)), 0);
nextNode = extension.node;
} else {
break;
}
} else if (TrieDB.isBranch(node)) {
Branch memory branch = EthereumTrieDB.decodeBranch(node);
if (NibbleSliceOps.isEmpty(keyNibbles)) {
if (Option.isSome(branch.value)) {
return true;
}
break;
} else {
NodeHandleOption memory handle = branch.children[NibbleSliceOps.at(keyNibbles, 0)];
if (Option.isSome(handle)) {
keyNibbles = NibbleSliceOps.mid(keyNibbles, 1);
nextNode = handle.value;
} else {
break;
}
}
} else if (TrieDB.isEmpty(node)) {
break;
}
node = EthereumTrieDB.decodeNodeKind(TrieDB.load(nodes, nextNode));
}
return false;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: Apache2
pragma solidity 0.8.23;
import "./NibbleSlice.sol";
import "./Bytes.sol";
/// This is an enum for the different node types.
struct NodeKind {
bool isEmpty;
bool isLeaf;
bool isHashedLeaf;
bool isNibbledValueBranch;
bool isNibbledHashedValueBranch;
bool isNibbledBranch;
bool isExtension;
bool isBranch;
uint256 nibbleSize;
ByteSlice data;
}
struct NodeHandle {
bool isHash;
bytes32 hash;
bool isInline;
bytes inLine;
}
struct Extension {
NibbleSlice key;
NodeHandle node;
}
struct Branch {
NodeHandleOption value;
NodeHandleOption[16] children;
}
struct NibbledBranch {
NibbleSlice key;
NodeHandleOption value;
NodeHandleOption[16] children;
}
struct ValueOption {
bool isSome;
bytes value;
}
struct NodeHandleOption {
bool isSome;
NodeHandle value;
}
struct Leaf {
NibbleSlice key;
NodeHandle value;
}
struct TrieNode {
bytes32 hash;
bytes node;
}// SPDX-License-Identifier: Apache2
pragma solidity 0.8.23;
import "./Node.sol";
library Option {
function isSome(ValueOption memory val) internal pure returns (bool) {
return val.isSome == true;
}
function isSome(NodeHandleOption memory val) internal pure returns (bool) {
return val.isSome == true;
}
}// SPDX-License-Identifier: Apache2
pragma solidity 0.8.23;
struct NibbleSlice {
bytes data;
uint256 offset;
}
library NibbleSliceOps {
uint256 internal constant NIBBLE_PER_BYTE = 2;
uint256 internal constant BITS_PER_NIBBLE = 4;
function len(NibbleSlice memory nibble) internal pure returns (uint256) {
return nibble.data.length * NIBBLE_PER_BYTE - nibble.offset;
}
function mid(NibbleSlice memory self, uint256 i) internal pure returns (NibbleSlice memory) {
return NibbleSlice(self.data, self.offset + i);
}
function isEmpty(NibbleSlice memory self) internal pure returns (bool) {
return len(self) == 0;
}
function eq(NibbleSlice memory self, NibbleSlice memory other) internal pure returns (bool) {
return len(self) == len(other) && startsWith(self, other);
}
function at(NibbleSlice memory self, uint256 i) internal pure returns (uint256) {
uint256 ix = (self.offset + i) / NIBBLE_PER_BYTE;
uint256 pad = (self.offset + i) % NIBBLE_PER_BYTE;
uint8 data = uint8(self.data[ix]);
return (pad == 1) ? data & 0x0F : data >> BITS_PER_NIBBLE;
}
function startsWith(NibbleSlice memory self, NibbleSlice memory other) internal pure returns (bool) {
return commonPrefix(self, other) == len(other);
}
function commonPrefix(NibbleSlice memory self, NibbleSlice memory other) internal pure returns (uint256) {
uint256 self_align = self.offset % NIBBLE_PER_BYTE;
uint256 other_align = other.offset % NIBBLE_PER_BYTE;
if (self_align == other_align) {
uint256 self_start = self.offset / NIBBLE_PER_BYTE;
uint256 other_start = other.offset / NIBBLE_PER_BYTE;
uint256 first = 0;
if (self_align != 0) {
if ((self.data[self_start] & 0x0F) != (other.data[other_start] & 0x0F)) {
return 0;
}
++self_start;
++other_start;
++first;
}
bytes memory selfSlice = bytesSlice(self.data, self_start);
bytes memory otherSlice = bytesSlice(other.data, other_start);
return biggestDepth(selfSlice, otherSlice) + first;
} else {
uint256 s = min(len(self), len(other));
uint256 i = 0;
while (i < s) {
if (at(self, i) != at(other, i)) {
break;
}
++i;
}
return i;
}
}
function biggestDepth(bytes memory a, bytes memory b) internal pure returns (uint256) {
uint256 upperBound = min(a.length, b.length);
uint256 i = 0;
while (i < upperBound) {
if (a[i] != b[i]) {
return i * NIBBLE_PER_BYTE + leftCommon(a[i], b[i]);
}
++i;
}
return i * NIBBLE_PER_BYTE;
}
function leftCommon(bytes1 a, bytes1 b) internal pure returns (uint256) {
if (a == b) {
return 2;
} else if (uint8(a) & 0xF0 == uint8(b) & 0xF0) {
return 1;
} else {
return 0;
}
}
function bytesSlice(bytes memory _bytes, uint256 _start) internal pure returns (bytes memory) {
uint256 bytesLength = _bytes.length;
uint256 _length = bytesLength - _start;
require(bytesLength >= _start, "slice_outOfBounds");
bytes memory tempBytes;
assembly {
switch iszero(_length)
case 0 {
tempBytes := mload(0x40) // load free memory pointer
let lengthmod := and(_length, 31)
let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
let end := add(mc, _length)
for { let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start) } lt(mc, end) {
mc := add(mc, 0x20)
cc := add(cc, 0x20)
} { mstore(mc, mload(cc)) }
mstore(tempBytes, _length)
mstore(0x40, and(add(mc, 31), not(31)))
}
default {
tempBytes := mload(0x40)
mstore(tempBytes, 0)
mstore(0x40, add(tempBytes, 0x20))
}
}
return tempBytes;
}
function min(uint256 a, uint256 b) private pure returns (uint256) {
return (a < b) ? a : b;
}
}// SPDX-License-Identifier: Apache2
pragma solidity 0.8.23;
import "./Node.sol";
library TrieDB {
function get(TrieNode[] memory nodes, bytes32 hash) internal pure returns (bytes memory) {
for (uint256 i = 0; i < nodes.length; i++) {
if (nodes[i].hash == hash) {
return nodes[i].node;
}
}
revert("Incomplete Proof!");
}
function load(TrieNode[] memory nodes, NodeHandle memory node) internal pure returns (bytes memory) {
if (node.isInline) {
return node.inLine;
} else if (node.isHash) {
return get(nodes, node.hash);
}
return bytes("");
}
function isNibbledBranch(NodeKind memory node) internal pure returns (bool) {
return (node.isNibbledBranch || node.isNibbledHashedValueBranch || node.isNibbledValueBranch);
}
function isExtension(NodeKind memory node) internal pure returns (bool) {
return node.isExtension;
}
function isBranch(NodeKind memory node) internal pure returns (bool) {
return node.isBranch;
}
function isLeaf(NodeKind memory node) internal pure returns (bool) {
return (node.isLeaf || node.isHashedLeaf);
}
function isEmpty(NodeKind memory node) internal pure returns (bool) {
return node.isEmpty;
}
function isHash(NodeHandle memory node) internal pure returns (bool) {
return node.isHash;
}
function isInline(NodeHandle memory node) internal pure returns (bool) {
return node.isInline;
}
}// SPDX-License-Identifier: Apache2
pragma solidity 0.8.23;
import "../Node.sol";
import "../Bytes.sol";
import { NibbleSliceOps } from "../NibbleSlice.sol";
import "./RLPReader.sol";
library EthereumTrieDB {
using RLPReader for bytes;
using RLPReader for RLPReader.RLPItem;
using RLPReader for RLPReader.Iterator;
bytes constant HASHED_NULL_NODE = hex"56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421";
function decodeNodeKind(bytes memory encoded) internal pure returns (NodeKind memory) {
NodeKind memory node;
ByteSlice memory input = ByteSlice(encoded, 0);
if (Bytes.equals(encoded, HASHED_NULL_NODE)) {
node.isEmpty = true;
return node;
}
RLPReader.RLPItem[] memory itemList = encoded.toRlpItem().toList();
uint256 numItems = itemList.length;
if (numItems == 0) {
node.isEmpty = true;
return node;
} else if (numItems == 2) {
//It may be a leaf or extension
bytes memory key = itemList[0].toBytes();
uint256 prefix;
assembly {
let first := shr(248, mload(add(key, 32)))
prefix := shr(4, first)
}
if (prefix == 2 || prefix == 3) {
node.isLeaf = true;
} else {
node.isExtension = true;
}
} else if (numItems == 17) {
node.isBranch = true;
} else {
revert("Invalid data");
}
node.data = input;
return node;
}
function decodeLeaf(NodeKind memory node) internal pure returns (Leaf memory) {
Leaf memory leaf;
RLPReader.RLPItem[] memory decoded = node.data.data.toRlpItem().toList();
bytes memory data = decoded[1].toBytes();
//Remove the first byte, which is the prefix and not present in the user provided key
leaf.key = NibbleSlice(Bytes.substr(decoded[0].toBytes(), 1), 0);
leaf.value = NodeHandle(false, bytes32(0), true, data);
return leaf;
}
function decodeExtension(NodeKind memory node) internal pure returns (Extension memory) {
Extension memory extension;
RLPReader.RLPItem[] memory decoded = node.data.data.toRlpItem().toList();
bytes memory data = decoded[1].toBytes();
//Remove the first byte, which is the prefix and not present in the user provided key
extension.key = NibbleSlice(Bytes.substr(decoded[0].toBytes(), 1), 0);
extension.node = NodeHandle(true, Bytes.toBytes32(data), false, new bytes(0));
return extension;
}
function decodeBranch(NodeKind memory node) internal pure returns (Branch memory) {
Branch memory branch;
RLPReader.RLPItem[] memory decoded = node.data.data.toRlpItem().toList();
NodeHandleOption[16] memory childrens;
for (uint256 i = 0; i < 16; i++) {
bytes memory dataAsBytes = decoded[i].toBytes();
if (dataAsBytes.length != 32) {
childrens[i] = NodeHandleOption(false, NodeHandle(false, bytes32(0), false, new bytes(0)));
} else {
bytes32 data = Bytes.toBytes32(dataAsBytes);
childrens[i] = NodeHandleOption(true, NodeHandle(true, data, false, new bytes(0)));
}
}
if (isEmpty(decoded[16].toBytes())) {
branch.value = NodeHandleOption(false, NodeHandle(false, bytes32(0), false, new bytes(0)));
} else {
branch.value = NodeHandleOption(true, NodeHandle(false, bytes32(0), true, decoded[16].toBytes()));
}
branch.children = childrens;
return branch;
}
function isEmpty(bytes memory item) internal pure returns (bool) {
return item.length > 0 && (item[0] == 0xc0 || item[0] == 0x80);
}
}// SPDX-License-Identifier: Apache2
pragma solidity 0.8.23;
import { Memory } from "./Memory.sol";
struct ByteSlice {
bytes data;
uint256 offset;
}
library Bytes {
uint256 internal constant BYTES_HEADER_SIZE = 32;
// Checks if two `bytes memory` variables are equal. This is done using hashing,
// which is much more gas efficient then comparing each byte individually.
// Equality means that:
// - 'self.length == other.length'
// - For 'n' in '[0, self.length)', 'self[n] == other[n]'
function equals(bytes memory self, bytes memory other) internal pure returns (bool equal) {
if (self.length != other.length) {
return false;
}
uint256 addr;
uint256 addr2;
assembly {
addr := add(self, /*BYTES_HEADER_SIZE*/ 32)
addr2 := add(other, /*BYTES_HEADER_SIZE*/ 32)
}
equal = Memory.equals(addr, addr2, self.length);
}
function readByte(ByteSlice memory self) internal pure returns (uint8) {
if (self.offset + 1 > self.data.length) {
revert("Out of range");
}
uint8 b = uint8(self.data[self.offset]);
self.offset += 1;
return b;
}
// Copies 'len' bytes from 'self' into a new array, starting at the provided 'startIndex'.
// Returns the new copy.
// Requires that:
// - 'startIndex + len <= self.length'
// The length of the substring is: 'len'
function read(ByteSlice memory self, uint256 len) internal pure returns (bytes memory) {
require(self.offset + len <= self.data.length);
if (len == 0) {
return "";
}
uint256 addr = Memory.dataPtr(self.data);
bytes memory slice = Memory.toBytes(addr + self.offset, len);
self.offset += len;
return slice;
}
// Copies a section of 'self' into a new array, starting at the provided 'startIndex'.
// Returns the new copy.
// Requires that 'startIndex <= self.length'
// The length of the substring is: 'self.length - startIndex'
function substr(bytes memory self, uint256 startIndex) internal pure returns (bytes memory) {
require(startIndex <= self.length);
uint256 len = self.length - startIndex;
uint256 addr = Memory.dataPtr(self);
return Memory.toBytes(addr + startIndex, len);
}
// Copies 'len' bytes from 'self' into a new array, starting at the provided 'startIndex'.
// Returns the new copy.
// Requires that:
// - 'startIndex + len <= self.length'
// The length of the substring is: 'len'
function substr(bytes memory self, uint256 startIndex, uint256 len) internal pure returns (bytes memory) {
require(startIndex + len <= self.length);
if (len == 0) {
return "";
}
uint256 addr = Memory.dataPtr(self);
return Memory.toBytes(addr + startIndex, len);
}
// Combines 'self' and 'other' into a single array.
// Returns the concatenated arrays:
// [self[0], self[1], ... , self[self.length - 1], other[0], other[1], ... , other[other.length - 1]]
// The length of the new array is 'self.length + other.length'
function concat(bytes memory self, bytes memory other) internal pure returns (bytes memory) {
bytes memory ret = new bytes(self.length + other.length);
uint256 src;
uint256 srcLen;
(src, srcLen) = Memory.fromBytes(self);
uint256 src2;
uint256 src2Len;
(src2, src2Len) = Memory.fromBytes(other);
uint256 dest;
(dest,) = Memory.fromBytes(ret);
uint256 dest2 = dest + srcLen;
Memory.copy(src, dest, srcLen);
Memory.copy(src2, dest2, src2Len);
return ret;
}
function toBytes32(bytes memory self) internal pure returns (bytes32 out) {
require(self.length >= 32, "Bytes:: toBytes32: data is to short.");
assembly {
out := mload(add(self, 32))
}
}
function toBytes16(bytes memory self, uint256 offset) internal pure returns (bytes16 out) {
for (uint256 i = 0; i < 16; i++) {
out |= bytes16(bytes1(self[offset + i]) & 0xFF) >> (i * 8);
}
}
function toBytes8(bytes memory self, uint256 offset) internal pure returns (bytes8 out) {
for (uint256 i = 0; i < 8; i++) {
out |= bytes8(bytes1(self[offset + i]) & 0xFF) >> (i * 8);
}
}
function toBytes4(bytes memory self, uint256 offset) internal pure returns (bytes4) {
bytes4 out;
for (uint256 i = 0; i < 4; i++) {
out |= bytes4(self[offset + i] & 0xFF) >> (i * 8);
}
return out;
}
function toBytes2(bytes memory self, uint256 offset) internal pure returns (bytes2) {
bytes2 out;
for (uint256 i = 0; i < 2; i++) {
out |= bytes2(self[offset + i] & 0xFF) >> (i * 8);
}
return out;
}
function removeLeadingZero(bytes memory data) internal pure returns (bytes memory) {
uint256 length = data.length;
uint256 startIndex = 0;
for (uint256 i = 0; i < length; i++) {
if (data[i] != 0) {
startIndex = i;
break;
}
}
return substr(data, startIndex);
}
function removeEndingZero(bytes memory data) internal pure returns (bytes memory) {
uint256 length = data.length;
uint256 endIndex = 0;
for (uint256 i = length - 1; i >= 0; i--) {
if (data[i] != 0) {
endIndex = i;
break;
}
}
return substr(data, 0, endIndex + 1);
}
function reverse(bytes memory inbytes) internal pure returns (bytes memory) {
uint256 inlength = inbytes.length;
bytes memory outbytes = new bytes(inlength);
for (uint256 i = 0; i <= inlength - 1; i++) {
outbytes[i] = inbytes[inlength - i - 1];
}
return outbytes;
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.23;
library RLPReader {
uint8 constant STRING_SHORT_START = 0x80;
uint8 constant STRING_LONG_START = 0xb8;
uint8 constant LIST_SHORT_START = 0xc0;
uint8 constant LIST_LONG_START = 0xf8;
uint8 constant WORD_SIZE = 32;
struct RLPItem {
uint256 len;
uint256 memPtr;
}
struct Iterator {
RLPItem item; // Item that's being iterated over.
uint256 nextPtr; // Position of the next item in the list.
}
/*
* @dev Returns the next element in the iteration. Reverts if it has not next element.
* @param self The iterator.
* @return The next element in the iteration.
*/
function next(Iterator memory self) internal pure returns (RLPItem memory) {
require(hasNext(self));
uint256 ptr = self.nextPtr;
uint256 itemLength = _itemLength(ptr);
self.nextPtr = ptr + itemLength;
return RLPItem(itemLength, ptr);
}
/*
* @dev Returns true if the iteration has more elements.
* @param self The iterator.
* @return true if the iteration has more elements.
*/
function hasNext(Iterator memory self) internal pure returns (bool) {
RLPItem memory item = self.item;
return self.nextPtr < item.memPtr + item.len;
}
/*
* @param item RLP encoded bytes
*/
function toRlpItem(bytes memory item) internal pure returns (RLPItem memory) {
uint256 memPtr;
assembly {
memPtr := add(item, 0x20)
}
return RLPItem(item.length, memPtr);
}
/*
* @dev Create an iterator. Reverts if item is not a list.
* @param self The RLP item.
* @return An 'Iterator' over the item.
*/
function iterator(RLPItem memory self) internal pure returns (Iterator memory) {
require(isList(self));
uint256 ptr = self.memPtr + _payloadOffset(self.memPtr);
return Iterator(self, ptr);
}
/*
* @param the RLP item.
*/
function rlpLen(RLPItem memory item) internal pure returns (uint256) {
return item.len;
}
/*
* @param the RLP item.
* @return (memPtr, len) pair: location of the item's payload in memory.
*/
function payloadLocation(RLPItem memory item) internal pure returns (uint256, uint256) {
uint256 offset = _payloadOffset(item.memPtr);
uint256 memPtr = item.memPtr + offset;
uint256 len = item.len - offset; // data length
return (memPtr, len);
}
/*
* @param the RLP item.
*/
function payloadLen(RLPItem memory item) internal pure returns (uint256) {
(, uint256 len) = payloadLocation(item);
return len;
}
/*
* @param the RLP item containing the encoded list.
*/
function toList(RLPItem memory item) internal pure returns (RLPItem[] memory) {
require(isList(item));
uint256 items = numItems(item);
RLPItem[] memory result = new RLPItem[](items);
uint256 memPtr = item.memPtr + _payloadOffset(item.memPtr);
uint256 dataLen;
for (uint256 i = 0; i < items; i++) {
dataLen = _itemLength(memPtr);
result[i] = RLPItem(dataLen, memPtr);
memPtr = memPtr + dataLen;
}
return result;
}
// @return indicator whether encoded payload is a list. negate this function call for isData.
function isList(RLPItem memory item) internal pure returns (bool) {
if (item.len == 0) return false;
uint8 byte0;
uint256 memPtr = item.memPtr;
assembly {
byte0 := byte(0, mload(memPtr))
}
if (byte0 < LIST_SHORT_START) return false;
return true;
}
/*
* @dev A cheaper version of keccak256(toRlpBytes(item)) that avoids copying memory.
* @return keccak256 hash of RLP encoded bytes.
*/
function rlpBytesKeccak256(RLPItem memory item) internal pure returns (bytes32) {
uint256 ptr = item.memPtr;
uint256 len = item.len;
bytes32 result;
assembly {
result := keccak256(ptr, len)
}
return result;
}
/*
* @dev A cheaper version of keccak256(toBytes(item)) that avoids copying memory.
* @return keccak256 hash of the item payload.
*/
function payloadKeccak256(RLPItem memory item) internal pure returns (bytes32) {
(uint256 memPtr, uint256 len) = payloadLocation(item);
bytes32 result;
assembly {
result := keccak256(memPtr, len)
}
return result;
}
/**
* RLPItem conversions into data types *
*/
// @returns raw rlp encoding in bytes
function toRlpBytes(RLPItem memory item) internal pure returns (bytes memory) {
bytes memory result = new bytes(item.len);
if (result.length == 0) return result;
uint256 ptr;
assembly {
ptr := add(0x20, result)
}
copy(item.memPtr, ptr, item.len);
return result;
}
// any non-zero byte except "0x80" is considered true
function toBoolean(RLPItem memory item) internal pure returns (bool) {
require(item.len == 1);
uint256 result;
uint256 memPtr = item.memPtr;
assembly {
result := byte(0, mload(memPtr))
}
// SEE Github Issue #5.
// Summary: Most commonly used RLP libraries (i.e Geth) will encode
// "0" as "0x80" instead of as "0". We handle this edge case explicitly
// here.
if (result == 0 || result == STRING_SHORT_START) {
return false;
} else {
return true;
}
}
function toAddress(RLPItem memory item) internal pure returns (address) {
// 1 byte for the length prefix
require(item.len == 21);
return address(uint160(toUint(item)));
}
function toUint(RLPItem memory item) internal pure returns (uint256) {
require(item.len > 0 && item.len <= 33);
(uint256 memPtr, uint256 len) = payloadLocation(item);
uint256 result;
assembly {
result := mload(memPtr)
// shift to the correct location if neccesary
if lt(len, 32) { result := div(result, exp(256, sub(32, len))) }
}
return result;
}
// enforces 32 byte length
function toUintStrict(RLPItem memory item) internal pure returns (uint256) {
// one byte prefix
require(item.len == 33);
uint256 result;
uint256 memPtr = item.memPtr + 1;
assembly {
result := mload(memPtr)
}
return result;
}
function toBytes(RLPItem memory item) internal pure returns (bytes memory) {
require(item.len > 0);
(uint256 memPtr, uint256 len) = payloadLocation(item);
bytes memory result = new bytes(len);
uint256 destPtr;
assembly {
destPtr := add(0x20, result)
}
copy(memPtr, destPtr, len);
return result;
}
/*
* Private Helpers
*/
// @return number of payload items inside an encoded list.
function numItems(RLPItem memory item) private pure returns (uint256) {
if (item.len == 0) return 0;
uint256 count = 0;
uint256 currPtr = item.memPtr + _payloadOffset(item.memPtr);
uint256 endPtr = item.memPtr + item.len;
while (currPtr < endPtr) {
currPtr = currPtr + _itemLength(currPtr); // skip over an item
count++;
}
return count;
}
// @return entire rlp item byte length
function _itemLength(uint256 memPtr) private pure returns (uint256) {
uint256 itemLen;
uint256 byte0;
assembly {
byte0 := byte(0, mload(memPtr))
}
if (byte0 < STRING_SHORT_START) {
itemLen = 1;
} else if (byte0 < STRING_LONG_START) {
itemLen = byte0 - STRING_SHORT_START + 1;
} else if (byte0 < LIST_SHORT_START) {
assembly {
let byteLen := sub(byte0, 0xb7) // # of bytes the actual length is
memPtr := add(memPtr, 1) // skip over the first byte
/* 32 byte word size */
let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to get the len
itemLen := add(dataLen, add(byteLen, 1))
}
} else if (byte0 < LIST_LONG_START) {
itemLen = byte0 - LIST_SHORT_START + 1;
} else {
assembly {
let byteLen := sub(byte0, 0xf7)
memPtr := add(memPtr, 1)
let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to the correct length
itemLen := add(dataLen, add(byteLen, 1))
}
}
return itemLen;
}
// @return number of bytes until the data
function _payloadOffset(uint256 memPtr) private pure returns (uint256) {
uint256 byte0;
assembly {
byte0 := byte(0, mload(memPtr))
}
if (byte0 < STRING_SHORT_START) {
return 0;
} else if (byte0 < STRING_LONG_START || (byte0 >= LIST_SHORT_START && byte0 < LIST_LONG_START)) {
return 1;
} else if (byte0 < LIST_SHORT_START) {
// being explicit
return byte0 - (STRING_LONG_START - 1) + 1;
} else {
return byte0 - (LIST_LONG_START - 1) + 1;
}
}
/*
* @param src Pointer to source
* @param dest Pointer to destination
* @param len Amount of memory to copy from the source
*/
function copy(uint256 src, uint256 dest, uint256 len) private pure {
if (len == 0) return;
// copy as many word sizes as possible
for (; len >= WORD_SIZE; len -= WORD_SIZE) {
assembly {
mstore(dest, mload(src))
}
src += WORD_SIZE;
dest += WORD_SIZE;
}
if (len > 0) {
// left over bytes. Mask is used to remove unwanted bytes from the word
uint256 mask = 256 ** (WORD_SIZE - len) - 1;
assembly {
let srcpart := and(mload(src), not(mask)) // zero out src
let destpart := and(mload(dest), mask) // retrieve the bytes
mstore(dest, or(destpart, srcpart))
}
}
}
}// SPDX-License-Identifier: Apache2
pragma solidity 0.8.23;
library Memory {
uint256 internal constant WORD_SIZE = 32;
// Compares the 'len' bytes starting at address 'addr' in memory with the 'len'
// bytes starting at 'addr2'.
// Returns 'true' if the bytes are the same, otherwise 'false'.
function equals(uint256 addr, uint256 addr2, uint256 len) internal pure returns (bool equal) {
assembly {
equal := eq(keccak256(addr, len), keccak256(addr2, len))
}
}
// Compares the 'len' bytes starting at address 'addr' in memory with the bytes stored in
// 'bts'. It is allowed to set 'len' to a lower value then 'bts.length', in which case only
// the first 'len' bytes will be compared.
// Requires that 'bts.length >= len'
function equals(uint256 addr, uint256 len, bytes memory bts) internal pure returns (bool equal) {
require(bts.length >= len);
uint256 addr2;
assembly {
addr2 := add(bts, /*BYTES_HEADER_SIZE*/ 32)
}
return equals(addr, addr2, len);
}
// Returns a memory pointer to the data portion of the provided bytes array.
function dataPtr(bytes memory bts) internal pure returns (uint256 addr) {
assembly {
addr := add(bts, /*BYTES_HEADER_SIZE*/ 32)
}
}
// Creates a 'bytes memory' variable from the memory address 'addr', with the
// length 'len'. The function will allocate new memory for the bytes array, and
// the 'len bytes starting at 'addr' will be copied into that new memory.
function toBytes(uint256 addr, uint256 len) internal pure returns (bytes memory bts) {
bts = new bytes(len);
uint256 btsptr;
assembly {
btsptr := add(bts, /*BYTES_HEADER_SIZE*/ 32)
}
copy(addr, btsptr, len);
}
// Copies 'self' into a new 'bytes memory'.
// Returns the newly created 'bytes memory'
// The returned bytes will be of length '32'.
function toBytes(bytes32 self) internal pure returns (bytes memory bts) {
bts = new bytes(32);
assembly {
mstore(add(bts, /*BYTES_HEADER_SIZE*/ 32), self)
}
}
// Copy 'len' bytes from memory address 'src', to address 'dest'.
// This function does not check the or destination, it only copies
// the bytes.
function copy(uint256 src, uint256 dest, uint256 len) internal pure {
// Copy word-length chunks while possible
for (; len >= WORD_SIZE; len -= WORD_SIZE) {
assembly {
mstore(dest, mload(src))
}
dest += WORD_SIZE;
src += WORD_SIZE;
}
// Copy remaining bytes
uint256 mask = len == 0
? 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
: 256 ** (WORD_SIZE - len) - 1;
assembly {
let srcpart := and(mload(src), not(mask))
let destpart := and(mload(dest), mask)
mstore(dest, or(destpart, srcpart))
}
}
// This function does the same as 'dataPtr(bytes memory)', but will also return the
// length of the provided bytes array.
function fromBytes(bytes memory bts) internal pure returns (uint256 addr, uint256 len) {
len = bts.length;
assembly {
addr := add(bts, /*BYTES_HEADER_SIZE*/ 32)
}
}
}{
"remappings": [
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"forge-std/=lib/forge-std/src/",
"ds-test/=lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
"eth-gas-reporter/=node_modules/eth-gas-reporter/",
"hardhat/=node_modules/hardhat/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/"
],
"optimizer": {
"enabled": true,
"runs": 10000
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "none",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "paris",
"viaIR": false,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"initialOwner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyExists","type":"error"},{"inputs":[],"name":"NotAllowed","type":"error"},{"inputs":[],"name":"NotExists","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes32","name":"previousRoot","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"newRoot","type":"bytes32"},{"indexed":false,"internalType":"string","name":"dataUri","type":"string"}],"name":"MerkleRootUpdated","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":"relayerAddr","type":"address"}],"name":"RelayerAddressAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"relayerAddr","type":"address"}],"name":"RelayerAddressRemoved","type":"event"},{"inputs":[{"internalType":"address","name":"_relayerAddr","type":"address"}],"name":"addRelayer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getAllowedRelayers","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_relayerAddr","type":"address"}],"name":"isRelayerAllowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestDataUri","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestMerkleRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestRelayer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_relayerAddr","type":"address"}],"name":"removeRelayer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"root","type":"bytes32"},{"internalType":"string","name":"dataUri","type":"string"}],"name":"updateMerkleRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"},{"internalType":"bytes[]","name":"merkleProof","type":"bytes[]"},{"internalType":"bytes","name":"hash","type":"bytes"}],"name":"verifyMerkleProof","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"}]Contract Creation Code
60806040523480156200001157600080fd5b506040516200293f3803806200293f8339810160408190526200003491620000c7565b806001600160a01b0381166200006457604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b6200006f8162000077565b5050620000f9565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600060208284031215620000da57600080fd5b81516001600160a01b0381168114620000f257600080fd5b9392505050565b61283680620001096000396000f3fe608060405234801561001057600080fd5b50600436106100d45760003560e01c80638da5cb5b11610081578063dd39f00d1161005b578063dd39f00d146101d5578063e48034b5146101e8578063f2fde38b146101fb57600080fd5b80638da5cb5b1461018f578063ccae7f6b146101ad578063d98cbc8b146101c257600080fd5b806360f0a5ac116100b257806360f0a5ac1461015d5780636ac11d3b14610172578063715018a61461018757600080fd5b80632f850855146100d957806348ddb3f7146100f55780635e1c792a14610118575b600080fd5b6100e260035481565b6040519081526020015b60405180910390f35b610108610103366004612168565b61020e565b60405190151581526020016100ec565b6005546101389073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100ec565b61017061016b366004612259565b610225565b005b61017a6102b8565b6040516100ec919061228f565b61017061036e565b60005473ffffffffffffffffffffffffffffffffffffffff16610138565b6101b5610382565b6040516100ec91906122e9565b6101086101d0366004612259565b610410565b6101706101e3366004612259565b610423565b6101706101f6366004612338565b6104b6565b610170610209366004612259565b61057e565b600061021b8484846105e7565b90505b9392505050565b61022d610914565b600061023a600183610967565b905080610273576040517f5861b41d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405173ffffffffffffffffffffffffffffffffffffffff8316907ff0729ff1e41c7b30ab700244ba4e6e5cc18209a09f842e8bf1bab7762d0ef3dc90600090a25050565b606060006102c66001610989565b67ffffffffffffffff8111156102de576102de612098565b604051908082528060200260200182016040528015610307578160200160208202803683370190505b50905060005b6103176001610989565b81101561036857610329600182610993565b82828151811061033b5761033b6123b4565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015260010161030d565b50919050565b610376610914565b610380600061099f565b565b6004805461038f906123e3565b80601f01602080910402602001604051908101604052809291908181526020018280546103bb906123e3565b80156104085780601f106103dd57610100808354040283529160200191610408565b820191906000526020600020905b8154815290600101906020018083116103eb57829003601f168201915b505050505081565b600061041d600183610a14565b92915050565b61042b610914565b6000610438600183610a43565b905080610471576040517f23369fa600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405173ffffffffffffffffffffffffffffffffffffffff8316907f0bb142cb3e51924e21a59a9e18d61a54e960bce50ef144e74111318e2920c36e90600090a25050565b6104c1600133610a14565b6104f7576040517f3d693ada00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6003805490849055600461050c838583612480565b50600580547fffffffffffffffffffffffff000000000000000000000000000000000000000016339081179091556040517fa73fd016054ff5ed7be8ea41f468626decc3f4b3181ec243120b6cfc393a4fb19061057090849088908890889061257d565b60405180910390a250505050565b610586610914565b73ffffffffffffffffffffffffffffffffffffffff81166105db576040517f1e4fbdf7000000000000000000000000000000000000000000000000000000008152600060048201526024015b60405180910390fd5b6105e48161099f565b50565b600080835167ffffffffffffffff81111561060457610604612098565b60405190808252806020026020018201604052801561064a57816020015b6040805180820190915260008152606060208201528152602001906001900390816106225790505b50905060005b84518110156106cc576040518060400160405280868381518110610676576106766123b4565b602002602001015180519060200120815260200186838151811061069c5761069c6123b4565b60200260200101518152508282815181106106b9576106b96123b4565b6020908102919091010152600101610650565b50604080518082019091528381526000602082018190526106f56106f08489610a65565b610b28565b905060005b603281101561090657604080516080810182526000808252602082018190529181019190915260608082015261072f83610d9a565b156107dd57600061073f84610daf565b905060006002866020015161075491906125e9565b1561077a576002866020015161076a919061262c565b610775906001612640565b61078b565b6002866020015161078b919061262c565b905060405180604001604052806107a6886000015184610e7b565b8152602001600081525095506107c0826000015187610f6b565b156107d557600197505050505050505061021e565b505050610906565b60c0830151156108515760006107f284610f91565b905061080285826000015161106a565b1561084457604051806040016040528061082c87600001516108278560000151611087565b610e7b565b8152602001600081525094508060200151915061084b565b5050610906565b506108ee565b60e0830151156108e1576000610866846110aa565b9050610871856112ca565b15610891578051511515600103610844576001965050505050505061021e565b600081602001516108a38760006112dc565b601081106108b3576108b36123b4565b6020020151805190915015156001036107d5576108d1866001611366565b95508060200151925050506108ee565b8251156108ee5750610906565b6108fb6106f086836113a9565b9250506001016106fa565b506000979650505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610380576040517f118cdaa70000000000000000000000000000000000000000000000000000000081523360048201526024016105d2565b600061021e8373ffffffffffffffffffffffffffffffffffffffff84166113f2565b600061041d825490565b600061021e83836114ec565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600183016020526040812054151561021e565b600061021e8373ffffffffffffffffffffffffffffffffffffffff8416611516565b606060005b8351811015610ac55782848281518110610a8657610a866123b4565b60200260200101516000015103610abd57838181518110610aa957610aa96123b4565b60200260200101516020015191505061041d565b600101610a6a565b506040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f496e636f6d706c6574652050726f6f662100000000000000000000000000000060448201526064016105d2565b610b8c60408051610140810182526000808252602080830182905282840182905260608084018390526080840183905260a0840183905260c0840183905260e084018390526101008401839052845180860190955284528301529061012082015290565b610bf060408051610140810182526000808252602080830182905282840182905260608084018390526080840183905260a0840183905260c0840183905260e084018390526101008401839052845180860190955284528301529061012082015290565b6000604051806040016040528085815260200160008152509050610c49846040518060400160405280602081526020017f56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421815250611565565b15610c5957506001815292915050565b6000610c94610c8f8660408051808201825260008082526020918201528151808301909252825182529182019181019190915290565b611595565b80519091506000819003610caf575050600182525092915050565b80600203610d16576000610cdc83600081518110610ccf57610ccf6123b4565b60200260200101516116a1565b602081015190915060fc1c6002811480610cf65750806003145b15610d075760016020870152610d0f565b600160c08701525b5050610d8c565b80601103610d2a57600160e0850152610d8c565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f496e76616c69642064617461000000000000000000000000000000000000000060448201526064016105d2565b505061012082015292915050565b600081602001518061041d5750506040015190565b610db7611fa9565b610dbf611fa9565b610120830151516040805180820182526000808252602091820181905282518084019093528351835292810190820152610df890611595565b90506000610e1282600181518110610ccf57610ccf6123b4565b90506040518060400160405280610e3f610e3885600081518110610ccf57610ccf6123b4565b600161171f565b81526000602091820181905291855260408051608081018252838152808301939093526001908301526060820192909252908301525092915050565b81516060906000610e8c8483612653565b905083821015610ef8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f736c6963655f6f75744f66426f756e647300000000000000000000000000000060448201526064016105d2565b606081158015610f175760405191506000825260208201604052610f61565b6040519150601f8316801560200281840101848101888315602002848c0101015b81831015610f50578051835260209283019201610f38565b5050848452601f01601f1916604052505b5095945050505050565b6000610f7682611087565b610f7f84611087565b14801561021e575061021e838361106a565b610f99611fa9565b610fa1611fa9565b610120830151516040805180820182526000808252602091820181905282518084019093528351835292810190820152610fda90611595565b90506000610ff482600181518110610ccf57610ccf6123b4565b9050604051806040016040528061101a610e3885600081518110610ccf57610ccf6123b4565b8152600060209182015290845260408051608081019091526001815290810161104283611757565b8152600060208083018290526040805192835282820181529092015284015250909392505050565b600061107582611087565b61107f84846117f2565b149392505050565b6000816020015160028360000151516110a09190612666565b61041d9190612653565b6110b2611ffa565b6110ba611ffa565b6101208301515160408051808201825260008082526020918201819052825180840190935283518352928101908201526110f390611595565b90506110fd612039565b60005b60108110156111fb576000611120848381518110610ccf57610ccf6123b4565b9050805160201461118857604080518082018252600080825282516080810184528181526020808201839052818501839052845192835282810190945260608101919091529181019190915283836010811061117e5761117e6123b4565b60200201526111f2565b600061119382611757565b604080518082018252600180825282516080810184529081526020808201859052600082850181905284519081528082019094526060820193909352918101919091529091508484601081106111eb576111eb6123b4565b6020020152505b50600101611100565b5061121a61121583601081518110610ccf57610ccf6123b4565b6119a8565b1561126757604080518082018252600080825282516080810184528181526020808201839052818501839052845192835282810190945260608101919091529181019190915283526112be565b604051806040016040528060011515815260200160405180608001604052806000151581526020016000801b81526020016001151581526020016112b786601081518110610ccf57610ccf6123b4565b9052905283525b60208301525092915050565b60006112d582611087565b1592915050565b60008060028385602001516112f19190612640565b6112fb919061262c565b9050600060028486602001516113119190612640565b61131b91906125e9565b9050600085600001518381518110611335576113356123b4565b016020015160f81c9050600182146113545760048160ff16901c611359565b80600f165b60ff169695505050505050565b6040805180820190915260608152600060208201526040518060400160405280846000015181526020018385602001516113a09190612640565b90529392505050565b60608160400151156113c05750606081015161041d565b8151156113dc576113d5838360200151610a65565b905061041d565b5060408051602081019091526000815292915050565b600081815260018301602052604081205480156114db576000611416600183612653565b855490915060009061142a90600190612653565b905080821461148f57600086600001828154811061144a5761144a6123b4565b906000526020600020015490508087600001848154811061146d5761146d6123b4565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806114a0576114a061267d565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061041d565b600091505061041d565b5092915050565b6000826000018281548110611503576115036123b4565b9060005260206000200154905092915050565b600081815260018301602052604081205461155d5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561041d565b50600061041d565b600081518351146115785750600061041d565b825160208381018281209186019283209091145b95945050505050565b60606115a082611a7b565b6115a957600080fd5b60006115b483611ab6565b905060008167ffffffffffffffff8111156115d1576115d1612098565b60405190808252806020026020018201604052801561161657816020015b60408051808201909152600080825260208201528152602001906001900390816115ef5790505b50905060006116288560200151611b3b565b85602001516116379190612640565b90506000805b848110156116965761164e83611bb6565b9150604051806040016040528083815260200184815250848281518110611677576116776123b4565b602090810291909101015261168c8284612640565b925060010161163d565b509195945050505050565b80516060906116af57600080fd5b6000806116bb84611c78565b9150915060008167ffffffffffffffff8111156116da576116da612098565b6040519080825280601f01601f191660200182016040528015611704576020820181803683370190505b50905060208101611716848285611cbf565b50949350505050565b6060825182111561172f57600080fd5b600082845161173e9190612653565b90506020840161158c6117518583612640565b83611d42565b60006020825110156117ea576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f42797465733a3a20746f427974657333323a206461746120697320746f20736860448201527f6f72742e0000000000000000000000000000000000000000000000000000000060648201526084016105d2565b506020015190565b6000806002846020015161180691906125e9565b905060006002846020015161181b91906125e9565b905080820361194b57600060028660200151611837919061262c565b905060006002866020015161184c919061262c565b90506000841561190457865180518390811061186a5761186a6123b4565b0160200151885180517f0f0000000000000000000000000000000000000000000000000000000000000090921691859081106118a8576118a86123b4565b01602001517f0f0000000000000000000000000000000000000000000000000000000000000016146118e25760009550505050505061041d565b6118eb836126ac565b92506118f6826126ac565b9150611901816126ac565b90505b6000611914896000015185610e7b565b90506000611926896000015185610e7b565b9050826119338383611d99565b61193d9190612640565b97505050505050505061041d565b600061196761195987611087565b61196287611087565b611ec9565b905060005b8181101561199d5761197e86826112dc565b61198888836112dc565b0361199d57611996816126ac565b905061196c565b935061041d92505050565b600080825111801561041d5750816000815181106119c8576119c86123b4565b6020910101517fff00000000000000000000000000000000000000000000000000000000000000167fc000000000000000000000000000000000000000000000000000000000000000148061041d575081600081518110611a2b57611a2b6123b4565b6020910101517fff00000000000000000000000000000000000000000000000000000000000000167f80000000000000000000000000000000000000000000000000000000000000001492915050565b80516000908103611a8e57506000919050565b6020820151805160001a9060c0821015611aac575060009392505050565b5060019392505050565b80516000908103611ac957506000919050565b600080611ad98460200151611b3b565b8460200151611ae89190612640565b9050600084600001518560200151611b009190612640565b90505b80821015611b3257611b1482611bb6565b611b1e9083612640565b915082611b2a816126ac565b935050611b03565b50909392505050565b8051600090811a6080811015611b545750600092915050565b60b8811080611b6f575060c08110801590611b6f575060f881105b15611b7d5750600192915050565b60c0811015611baa57611b92600160b86126e4565b611b9f9060ff1682612653565b61021e906001612640565b611b92600160f86126e4565b80516000908190811a6080811015611bd157600191506114e5565b60b8811015611bf757611be5608082612653565b611bf0906001612640565b91506114e5565b60c0811015611c245760b78103600185019450806020036101000a855104600182018101935050506114e5565b60f8811015611c3857611be560c082612653565b60019390930151602084900360f7016101000a90049092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0a0192915050565b6000806000611c8a8460200151611b3b565b90506000818560200151611c9e9190612640565b90506000828660000151611cb29190612653565b9196919550909350505050565b80600003611ccc57505050565b60208110611d045782518252611ce3602084612640565b9250611cf0602083612640565b9150611cfd602082612653565b9050611ccc565b8015611d3d5760006001611d19836020612653565b611d259061010061281d565b611d2f9190612653565b845184518216911916178352505b505050565b60608167ffffffffffffffff811115611d5d57611d5d612098565b6040519080825280601f01601f191660200182016040528015611d87576020820181803683370190505b509050602081016114e5848285611edf565b600080611da884518451611ec9565b905060005b81811015611ebe57838181518110611dc757611dc76123b4565b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916858281518110611e0657611e066123b4565b01602001517fff000000000000000000000000000000000000000000000000000000000000001614611eae57611e90858281518110611e4757611e476123b4565b602001015160f81c60f81b858381518110611e6457611e646123b4565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016611f4d565b611e9b600283612666565b611ea59190612640565b9250505061041d565b611eb7816126ac565b9050611dad565b61158c600282612666565b6000818310611ed8578161021e565b5090919050565b60208110611f175782518252611ef6602083612640565b9150611f03602084612640565b9250611f10602082612653565b9050611edf565b60008115611f47576001611f2c836020612653565b611f389061010061281d565b611f429190612653565b611d2f565b50505050565b60007fff0000000000000000000000000000000000000000000000000000000000000080831690841603611f835750600261041d565b8160f81c60f01660ff168360f81c60f01660ff160361155d5750600161041d565b905290565b6040518060400160405280611fd1604051806040016040528060608152602001600081525090565b815260408051608081018252600080825260208281018290529282015260608082015291015290565b6040805160808082018352600082840181815284519283018552818352602083018290529382015260608082018190528201529081908152602001611fa45b6040518061020001604052806010905b61208260408051808201825260008082528251608081018452818152602081810183905293810191909152606080820152909182015290565b8152602001906001900390816120495790505090565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff811182821017156120f0576120f0612098565b604052919050565b600082601f83011261210957600080fd5b813567ffffffffffffffff81111561212357612123612098565b6121366020601f19601f840116016120c7565b81815284602083860101111561214b57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060006060848603121561217d57600080fd5b8335925060208085013567ffffffffffffffff8082111561219d57600080fd5b818701915087601f8301126121b157600080fd5b8135818111156121c3576121c3612098565b8060051b6121d28582016120c7565b918252838101850191858101908b8411156121ec57600080fd5b86860192505b838310156122285782358581111561220a5760008081fd5b6122188d89838a01016120f8565b83525091860191908601906121f2565b9750505050604087013592508083111561224157600080fd5b505061224f868287016120f8565b9150509250925092565b60006020828403121561226b57600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461021e57600080fd5b6020808252825182820181905260009190848201906040850190845b818110156122dd57835173ffffffffffffffffffffffffffffffffffffffff16835292840192918401916001016122ab565b50909695505050505050565b60006020808352835180602085015260005b81811015612317578581018301518582016040015282016122fb565b506000604082860101526040601f19601f8301168501019250505092915050565b60008060006040848603121561234d57600080fd5b83359250602084013567ffffffffffffffff8082111561236c57600080fd5b818601915086601f83011261238057600080fd5b81358181111561238f57600080fd5b8760208285010111156123a157600080fd5b6020830194508093505050509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600181811c908216806123f757607f821691505b602082108103610368577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b601f821115611d3d576000816000526020600020601f850160051c810160208610156124595750805b601f850160051c820191505b8181101561247857828155600101612465565b505050505050565b67ffffffffffffffff83111561249857612498612098565b6124ac836124a683546123e3565b83612430565b6000601f8411600181146124fe57600085156124c85750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355612576565b600083815260209020601f19861690835b8281101561252f578685013582556020948501946001909201910161250f565b508682101561256a577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b84815283602082015260606040820152816060820152818360808301376000818301608090810191909152601f909201601f191601019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000826125f8576125f86125ba565b500690565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008261263b5761263b6125ba565b500490565b8082018082111561041d5761041d6125fd565b8181038181111561041d5761041d6125fd565b808202811582820484141761041d5761041d6125fd565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036126dd576126dd6125fd565b5060010190565b60ff828116828216039081111561041d5761041d6125fd565b600181815b8085111561275657817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561273c5761273c6125fd565b8085161561274957918102915b93841c9390800290612702565b509250929050565b60008261276d5750600161041d565b8161277a5750600061041d565b8160018114612790576002811461279a576127b6565b600191505061041d565b60ff8411156127ab576127ab6125fd565b50506001821b61041d565b5060208310610133831016604e8410600b84101617156127d9575081810a61041d565b6127e383836126fd565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115612815576128156125fd565b029392505050565b600061021e838361275e56fea164736f6c6343000817000a0000000000000000000000007df0808cfd89ea3995af99cb1374d2907c2399b6
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106100d45760003560e01c80638da5cb5b11610081578063dd39f00d1161005b578063dd39f00d146101d5578063e48034b5146101e8578063f2fde38b146101fb57600080fd5b80638da5cb5b1461018f578063ccae7f6b146101ad578063d98cbc8b146101c257600080fd5b806360f0a5ac116100b257806360f0a5ac1461015d5780636ac11d3b14610172578063715018a61461018757600080fd5b80632f850855146100d957806348ddb3f7146100f55780635e1c792a14610118575b600080fd5b6100e260035481565b6040519081526020015b60405180910390f35b610108610103366004612168565b61020e565b60405190151581526020016100ec565b6005546101389073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100ec565b61017061016b366004612259565b610225565b005b61017a6102b8565b6040516100ec919061228f565b61017061036e565b60005473ffffffffffffffffffffffffffffffffffffffff16610138565b6101b5610382565b6040516100ec91906122e9565b6101086101d0366004612259565b610410565b6101706101e3366004612259565b610423565b6101706101f6366004612338565b6104b6565b610170610209366004612259565b61057e565b600061021b8484846105e7565b90505b9392505050565b61022d610914565b600061023a600183610967565b905080610273576040517f5861b41d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405173ffffffffffffffffffffffffffffffffffffffff8316907ff0729ff1e41c7b30ab700244ba4e6e5cc18209a09f842e8bf1bab7762d0ef3dc90600090a25050565b606060006102c66001610989565b67ffffffffffffffff8111156102de576102de612098565b604051908082528060200260200182016040528015610307578160200160208202803683370190505b50905060005b6103176001610989565b81101561036857610329600182610993565b82828151811061033b5761033b6123b4565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015260010161030d565b50919050565b610376610914565b610380600061099f565b565b6004805461038f906123e3565b80601f01602080910402602001604051908101604052809291908181526020018280546103bb906123e3565b80156104085780601f106103dd57610100808354040283529160200191610408565b820191906000526020600020905b8154815290600101906020018083116103eb57829003601f168201915b505050505081565b600061041d600183610a14565b92915050565b61042b610914565b6000610438600183610a43565b905080610471576040517f23369fa600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405173ffffffffffffffffffffffffffffffffffffffff8316907f0bb142cb3e51924e21a59a9e18d61a54e960bce50ef144e74111318e2920c36e90600090a25050565b6104c1600133610a14565b6104f7576040517f3d693ada00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6003805490849055600461050c838583612480565b50600580547fffffffffffffffffffffffff000000000000000000000000000000000000000016339081179091556040517fa73fd016054ff5ed7be8ea41f468626decc3f4b3181ec243120b6cfc393a4fb19061057090849088908890889061257d565b60405180910390a250505050565b610586610914565b73ffffffffffffffffffffffffffffffffffffffff81166105db576040517f1e4fbdf7000000000000000000000000000000000000000000000000000000008152600060048201526024015b60405180910390fd5b6105e48161099f565b50565b600080835167ffffffffffffffff81111561060457610604612098565b60405190808252806020026020018201604052801561064a57816020015b6040805180820190915260008152606060208201528152602001906001900390816106225790505b50905060005b84518110156106cc576040518060400160405280868381518110610676576106766123b4565b602002602001015180519060200120815260200186838151811061069c5761069c6123b4565b60200260200101518152508282815181106106b9576106b96123b4565b6020908102919091010152600101610650565b50604080518082019091528381526000602082018190526106f56106f08489610a65565b610b28565b905060005b603281101561090657604080516080810182526000808252602082018190529181019190915260608082015261072f83610d9a565b156107dd57600061073f84610daf565b905060006002866020015161075491906125e9565b1561077a576002866020015161076a919061262c565b610775906001612640565b61078b565b6002866020015161078b919061262c565b905060405180604001604052806107a6886000015184610e7b565b8152602001600081525095506107c0826000015187610f6b565b156107d557600197505050505050505061021e565b505050610906565b60c0830151156108515760006107f284610f91565b905061080285826000015161106a565b1561084457604051806040016040528061082c87600001516108278560000151611087565b610e7b565b8152602001600081525094508060200151915061084b565b5050610906565b506108ee565b60e0830151156108e1576000610866846110aa565b9050610871856112ca565b15610891578051511515600103610844576001965050505050505061021e565b600081602001516108a38760006112dc565b601081106108b3576108b36123b4565b6020020151805190915015156001036107d5576108d1866001611366565b95508060200151925050506108ee565b8251156108ee5750610906565b6108fb6106f086836113a9565b9250506001016106fa565b506000979650505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610380576040517f118cdaa70000000000000000000000000000000000000000000000000000000081523360048201526024016105d2565b600061021e8373ffffffffffffffffffffffffffffffffffffffff84166113f2565b600061041d825490565b600061021e83836114ec565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600183016020526040812054151561021e565b600061021e8373ffffffffffffffffffffffffffffffffffffffff8416611516565b606060005b8351811015610ac55782848281518110610a8657610a866123b4565b60200260200101516000015103610abd57838181518110610aa957610aa96123b4565b60200260200101516020015191505061041d565b600101610a6a565b506040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f496e636f6d706c6574652050726f6f662100000000000000000000000000000060448201526064016105d2565b610b8c60408051610140810182526000808252602080830182905282840182905260608084018390526080840183905260a0840183905260c0840183905260e084018390526101008401839052845180860190955284528301529061012082015290565b610bf060408051610140810182526000808252602080830182905282840182905260608084018390526080840183905260a0840183905260c0840183905260e084018390526101008401839052845180860190955284528301529061012082015290565b6000604051806040016040528085815260200160008152509050610c49846040518060400160405280602081526020017f56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421815250611565565b15610c5957506001815292915050565b6000610c94610c8f8660408051808201825260008082526020918201528151808301909252825182529182019181019190915290565b611595565b80519091506000819003610caf575050600182525092915050565b80600203610d16576000610cdc83600081518110610ccf57610ccf6123b4565b60200260200101516116a1565b602081015190915060fc1c6002811480610cf65750806003145b15610d075760016020870152610d0f565b600160c08701525b5050610d8c565b80601103610d2a57600160e0850152610d8c565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f496e76616c69642064617461000000000000000000000000000000000000000060448201526064016105d2565b505061012082015292915050565b600081602001518061041d5750506040015190565b610db7611fa9565b610dbf611fa9565b610120830151516040805180820182526000808252602091820181905282518084019093528351835292810190820152610df890611595565b90506000610e1282600181518110610ccf57610ccf6123b4565b90506040518060400160405280610e3f610e3885600081518110610ccf57610ccf6123b4565b600161171f565b81526000602091820181905291855260408051608081018252838152808301939093526001908301526060820192909252908301525092915050565b81516060906000610e8c8483612653565b905083821015610ef8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f736c6963655f6f75744f66426f756e647300000000000000000000000000000060448201526064016105d2565b606081158015610f175760405191506000825260208201604052610f61565b6040519150601f8316801560200281840101848101888315602002848c0101015b81831015610f50578051835260209283019201610f38565b5050848452601f01601f1916604052505b5095945050505050565b6000610f7682611087565b610f7f84611087565b14801561021e575061021e838361106a565b610f99611fa9565b610fa1611fa9565b610120830151516040805180820182526000808252602091820181905282518084019093528351835292810190820152610fda90611595565b90506000610ff482600181518110610ccf57610ccf6123b4565b9050604051806040016040528061101a610e3885600081518110610ccf57610ccf6123b4565b8152600060209182015290845260408051608081019091526001815290810161104283611757565b8152600060208083018290526040805192835282820181529092015284015250909392505050565b600061107582611087565b61107f84846117f2565b149392505050565b6000816020015160028360000151516110a09190612666565b61041d9190612653565b6110b2611ffa565b6110ba611ffa565b6101208301515160408051808201825260008082526020918201819052825180840190935283518352928101908201526110f390611595565b90506110fd612039565b60005b60108110156111fb576000611120848381518110610ccf57610ccf6123b4565b9050805160201461118857604080518082018252600080825282516080810184528181526020808201839052818501839052845192835282810190945260608101919091529181019190915283836010811061117e5761117e6123b4565b60200201526111f2565b600061119382611757565b604080518082018252600180825282516080810184529081526020808201859052600082850181905284519081528082019094526060820193909352918101919091529091508484601081106111eb576111eb6123b4565b6020020152505b50600101611100565b5061121a61121583601081518110610ccf57610ccf6123b4565b6119a8565b1561126757604080518082018252600080825282516080810184528181526020808201839052818501839052845192835282810190945260608101919091529181019190915283526112be565b604051806040016040528060011515815260200160405180608001604052806000151581526020016000801b81526020016001151581526020016112b786601081518110610ccf57610ccf6123b4565b9052905283525b60208301525092915050565b60006112d582611087565b1592915050565b60008060028385602001516112f19190612640565b6112fb919061262c565b9050600060028486602001516113119190612640565b61131b91906125e9565b9050600085600001518381518110611335576113356123b4565b016020015160f81c9050600182146113545760048160ff16901c611359565b80600f165b60ff169695505050505050565b6040805180820190915260608152600060208201526040518060400160405280846000015181526020018385602001516113a09190612640565b90529392505050565b60608160400151156113c05750606081015161041d565b8151156113dc576113d5838360200151610a65565b905061041d565b5060408051602081019091526000815292915050565b600081815260018301602052604081205480156114db576000611416600183612653565b855490915060009061142a90600190612653565b905080821461148f57600086600001828154811061144a5761144a6123b4565b906000526020600020015490508087600001848154811061146d5761146d6123b4565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806114a0576114a061267d565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061041d565b600091505061041d565b5092915050565b6000826000018281548110611503576115036123b4565b9060005260206000200154905092915050565b600081815260018301602052604081205461155d5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561041d565b50600061041d565b600081518351146115785750600061041d565b825160208381018281209186019283209091145b95945050505050565b60606115a082611a7b565b6115a957600080fd5b60006115b483611ab6565b905060008167ffffffffffffffff8111156115d1576115d1612098565b60405190808252806020026020018201604052801561161657816020015b60408051808201909152600080825260208201528152602001906001900390816115ef5790505b50905060006116288560200151611b3b565b85602001516116379190612640565b90506000805b848110156116965761164e83611bb6565b9150604051806040016040528083815260200184815250848281518110611677576116776123b4565b602090810291909101015261168c8284612640565b925060010161163d565b509195945050505050565b80516060906116af57600080fd5b6000806116bb84611c78565b9150915060008167ffffffffffffffff8111156116da576116da612098565b6040519080825280601f01601f191660200182016040528015611704576020820181803683370190505b50905060208101611716848285611cbf565b50949350505050565b6060825182111561172f57600080fd5b600082845161173e9190612653565b90506020840161158c6117518583612640565b83611d42565b60006020825110156117ea576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f42797465733a3a20746f427974657333323a206461746120697320746f20736860448201527f6f72742e0000000000000000000000000000000000000000000000000000000060648201526084016105d2565b506020015190565b6000806002846020015161180691906125e9565b905060006002846020015161181b91906125e9565b905080820361194b57600060028660200151611837919061262c565b905060006002866020015161184c919061262c565b90506000841561190457865180518390811061186a5761186a6123b4565b0160200151885180517f0f0000000000000000000000000000000000000000000000000000000000000090921691859081106118a8576118a86123b4565b01602001517f0f0000000000000000000000000000000000000000000000000000000000000016146118e25760009550505050505061041d565b6118eb836126ac565b92506118f6826126ac565b9150611901816126ac565b90505b6000611914896000015185610e7b565b90506000611926896000015185610e7b565b9050826119338383611d99565b61193d9190612640565b97505050505050505061041d565b600061196761195987611087565b61196287611087565b611ec9565b905060005b8181101561199d5761197e86826112dc565b61198888836112dc565b0361199d57611996816126ac565b905061196c565b935061041d92505050565b600080825111801561041d5750816000815181106119c8576119c86123b4565b6020910101517fff00000000000000000000000000000000000000000000000000000000000000167fc000000000000000000000000000000000000000000000000000000000000000148061041d575081600081518110611a2b57611a2b6123b4565b6020910101517fff00000000000000000000000000000000000000000000000000000000000000167f80000000000000000000000000000000000000000000000000000000000000001492915050565b80516000908103611a8e57506000919050565b6020820151805160001a9060c0821015611aac575060009392505050565b5060019392505050565b80516000908103611ac957506000919050565b600080611ad98460200151611b3b565b8460200151611ae89190612640565b9050600084600001518560200151611b009190612640565b90505b80821015611b3257611b1482611bb6565b611b1e9083612640565b915082611b2a816126ac565b935050611b03565b50909392505050565b8051600090811a6080811015611b545750600092915050565b60b8811080611b6f575060c08110801590611b6f575060f881105b15611b7d5750600192915050565b60c0811015611baa57611b92600160b86126e4565b611b9f9060ff1682612653565b61021e906001612640565b611b92600160f86126e4565b80516000908190811a6080811015611bd157600191506114e5565b60b8811015611bf757611be5608082612653565b611bf0906001612640565b91506114e5565b60c0811015611c245760b78103600185019450806020036101000a855104600182018101935050506114e5565b60f8811015611c3857611be560c082612653565b60019390930151602084900360f7016101000a90049092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0a0192915050565b6000806000611c8a8460200151611b3b565b90506000818560200151611c9e9190612640565b90506000828660000151611cb29190612653565b9196919550909350505050565b80600003611ccc57505050565b60208110611d045782518252611ce3602084612640565b9250611cf0602083612640565b9150611cfd602082612653565b9050611ccc565b8015611d3d5760006001611d19836020612653565b611d259061010061281d565b611d2f9190612653565b845184518216911916178352505b505050565b60608167ffffffffffffffff811115611d5d57611d5d612098565b6040519080825280601f01601f191660200182016040528015611d87576020820181803683370190505b509050602081016114e5848285611edf565b600080611da884518451611ec9565b905060005b81811015611ebe57838181518110611dc757611dc76123b4565b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916858281518110611e0657611e066123b4565b01602001517fff000000000000000000000000000000000000000000000000000000000000001614611eae57611e90858281518110611e4757611e476123b4565b602001015160f81c60f81b858381518110611e6457611e646123b4565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016611f4d565b611e9b600283612666565b611ea59190612640565b9250505061041d565b611eb7816126ac565b9050611dad565b61158c600282612666565b6000818310611ed8578161021e565b5090919050565b60208110611f175782518252611ef6602083612640565b9150611f03602084612640565b9250611f10602082612653565b9050611edf565b60008115611f47576001611f2c836020612653565b611f389061010061281d565b611f429190612653565b611d2f565b50505050565b60007fff0000000000000000000000000000000000000000000000000000000000000080831690841603611f835750600261041d565b8160f81c60f01660ff168360f81c60f01660ff160361155d5750600161041d565b905290565b6040518060400160405280611fd1604051806040016040528060608152602001600081525090565b815260408051608081018252600080825260208281018290529282015260608082015291015290565b6040805160808082018352600082840181815284519283018552818352602083018290529382015260608082018190528201529081908152602001611fa45b6040518061020001604052806010905b61208260408051808201825260008082528251608081018452818152602081810183905293810191909152606080820152909182015290565b8152602001906001900390816120495790505090565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff811182821017156120f0576120f0612098565b604052919050565b600082601f83011261210957600080fd5b813567ffffffffffffffff81111561212357612123612098565b6121366020601f19601f840116016120c7565b81815284602083860101111561214b57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060006060848603121561217d57600080fd5b8335925060208085013567ffffffffffffffff8082111561219d57600080fd5b818701915087601f8301126121b157600080fd5b8135818111156121c3576121c3612098565b8060051b6121d28582016120c7565b918252838101850191858101908b8411156121ec57600080fd5b86860192505b838310156122285782358581111561220a5760008081fd5b6122188d89838a01016120f8565b83525091860191908601906121f2565b9750505050604087013592508083111561224157600080fd5b505061224f868287016120f8565b9150509250925092565b60006020828403121561226b57600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461021e57600080fd5b6020808252825182820181905260009190848201906040850190845b818110156122dd57835173ffffffffffffffffffffffffffffffffffffffff16835292840192918401916001016122ab565b50909695505050505050565b60006020808352835180602085015260005b81811015612317578581018301518582016040015282016122fb565b506000604082860101526040601f19601f8301168501019250505092915050565b60008060006040848603121561234d57600080fd5b83359250602084013567ffffffffffffffff8082111561236c57600080fd5b818601915086601f83011261238057600080fd5b81358181111561238f57600080fd5b8760208285010111156123a157600080fd5b6020830194508093505050509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600181811c908216806123f757607f821691505b602082108103610368577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b601f821115611d3d576000816000526020600020601f850160051c810160208610156124595750805b601f850160051c820191505b8181101561247857828155600101612465565b505050505050565b67ffffffffffffffff83111561249857612498612098565b6124ac836124a683546123e3565b83612430565b6000601f8411600181146124fe57600085156124c85750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355612576565b600083815260209020601f19861690835b8281101561252f578685013582556020948501946001909201910161250f565b508682101561256a577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b84815283602082015260606040820152816060820152818360808301376000818301608090810191909152601f909201601f191601019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000826125f8576125f86125ba565b500690565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008261263b5761263b6125ba565b500490565b8082018082111561041d5761041d6125fd565b8181038181111561041d5761041d6125fd565b808202811582820484141761041d5761041d6125fd565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036126dd576126dd6125fd565b5060010190565b60ff828116828216039081111561041d5761041d6125fd565b600181815b8085111561275657817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561273c5761273c6125fd565b8085161561274957918102915b93841c9390800290612702565b509250929050565b60008261276d5750600161041d565b8161277a5750600061041d565b8160018114612790576002811461279a576127b6565b600191505061041d565b60ff8411156127ab576127ab6125fd565b50506001821b61041d565b5060208310610133831016604e8410600b84101617156127d9575081810a61041d565b6127e383836126fd565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115612815576128156125fd565b029392505050565b600061021e838361275e56fea164736f6c6343000817000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000007df0808cfd89ea3995af99cb1374d2907c2399b6
-----Decoded View---------------
Arg [0] : initialOwner (address): 0x7DF0808CFD89Ea3995af99CB1374D2907C2399b6
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000007df0808cfd89ea3995af99cb1374d2907c2399b6
Loading...
Loading
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.