Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
Latest 25 from a total of 229 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Handle Consensus | 6485347 | 123 days ago | IN | 0 ETH | 0.02021351 | ||||
Handle Consensus | 6485078 | 123 days ago | IN | 0 ETH | 0.01526284 | ||||
Handle Consensus | 6484802 | 123 days ago | IN | 0 ETH | 0.04357265 | ||||
Handle Consensus | 6484536 | 123 days ago | IN | 0 ETH | 0.02129529 | ||||
Handle Consensus | 6484277 | 123 days ago | IN | 0 ETH | 0.02407591 | ||||
Handle Consensus | 6484028 | 123 days ago | IN | 0 ETH | 0.03128759 | ||||
Handle Consensus | 6483783 | 123 days ago | IN | 0 ETH | 0.01670123 | ||||
Handle Consensus | 6483555 | 123 days ago | IN | 0 ETH | 0.06281615 | ||||
Handle Consensus | 6483293 | 123 days ago | IN | 0 ETH | 0.00341621 | ||||
Handle Consensus | 6483040 | 123 days ago | IN | 0 ETH | 0.00128271 | ||||
Handle Consensus | 6482777 | 123 days ago | IN | 0 ETH | 0.00265464 | ||||
Handle Consensus | 6482506 | 123 days ago | IN | 0 ETH | 0.00658883 | ||||
Handle Consensus | 6482233 | 123 days ago | IN | 0 ETH | 0.00749551 | ||||
Handle Consensus | 6481968 | 123 days ago | IN | 0 ETH | 0.00225086 | ||||
Handle Consensus | 6481720 | 123 days ago | IN | 0 ETH | 0.01289311 | ||||
Handle Consensus | 6481433 | 123 days ago | IN | 0 ETH | 0.00659637 | ||||
Handle Consensus | 6481159 | 123 days ago | IN | 0 ETH | 0.00390793 | ||||
Handle Consensus | 6480890 | 123 days ago | IN | 0 ETH | 0.01027897 | ||||
Handle Consensus | 6480631 | 123 days ago | IN | 0 ETH | 0.00863291 | ||||
Handle Consensus | 6480372 | 124 days ago | IN | 0 ETH | 0.00925163 | ||||
Handle Consensus | 6480100 | 124 days ago | IN | 0 ETH | 0.00659063 | ||||
Handle Consensus | 6479825 | 124 days ago | IN | 0 ETH | 0.00956396 | ||||
Handle Consensus | 6479562 | 124 days ago | IN | 0 ETH | 0.03219956 | ||||
Handle Consensus | 6479300 | 124 days ago | IN | 0 ETH | 0.01446386 | ||||
Handle Consensus | 6479035 | 124 days ago | IN | 0 ETH | 0.00156256 |
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|
6429539 | 132 days ago | Contract Creation | 0 ETH |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
HandlerV1
Compiler Version
v0.8.17+commit.8df45f5f
Optimization Enabled:
Yes with 200 runs
Other Settings:
london EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// Copyright (C) Polytope Labs Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. pragma solidity 0.8.17; import {MerkleMountainRange, MmrLeaf} from "@polytope-labs/solidity-merkle-trees/MerkleMountainRange.sol"; import {MerklePatricia, StorageValue} from "@polytope-labs/solidity-merkle-trees/MerklePatricia.sol"; import {Bytes} from "@polytope-labs/solidity-merkle-trees/trie/Bytes.sol"; import {IConsensusClient, IntermediateState, StateMachineHeight, StateCommitment} from "@polytope-labs/ismp-solidity/IConsensusClient.sol"; import {IIsmpHost, FeeMetadata, FrozenStatus} from "@polytope-labs/ismp-solidity/IIsmpHost.sol"; import {IHandler} from "@polytope-labs/ismp-solidity/IHandler.sol"; import { Message, PostResponse, PostRequest, GetRequest, GetResponse, PostRequestMessage, PostResponseMessage, GetResponseMessage, PostRequestTimeoutMessage, PostResponseTimeoutMessage, GetTimeoutMessage, PostRequestLeaf, PostResponseLeaf } from "@polytope-labs/ismp-solidity/Message.sol"; import {Context} from "openzeppelin/utils/Context.sol"; import {ERC165} from "openzeppelin/utils/introspection/ERC165.sol"; // Storage prefix for request receipts in the pallet-ismp child trie bytes constant REQUEST_RECEIPTS_STORAGE_PREFIX = hex"526571756573745265636569707473"; // Storage prefix for response receipts in the pallet-ismp child trie bytes constant RESPONSE_RECEIPTS_STORAGE_PREFIX = hex"526573706f6e73655265636569707473"; /** * @title The ISMP Message Handler. * @author Polytope Labs ([email protected]) * * @notice The Handler is responsible for verifying the cryptographic proofs needed * to confirm the validity of incoming requests/responses. * Refer to the official ISMP specification. https://docs.hyperbridge.network/protocol/ismp */ contract HandlerV1 is IHandler, ERC165, Context { using Bytes for bytes; using Message for PostResponse; using Message for PostRequest; using Message for GetRequest; // The cosensus client has now expired to mitigate // long fork attacks, this is unrecoverable. error ConsensusClientExpired(); // The IsmpHost has been frozen by the admin error HostFrozen(); // Challenge period has not yet elapsed error ChallengePeriodNotElapsed(); // The requested state commitment does not exist error StateCommitmentNotFound(); // The message destination is not intended for this host error InvalidMessageDestination(); // The provided message has now timed-out error MessageTimedOut(); // The provided message has not timed-out error MessageNotTimedOut(); // The message has been previously processed error DuplicateMessage(); // The provided message is unknown to the host error UnknownMessage(); // The provided proof is invalid error InvalidProof(); /** * @dev Checks if the host permits incoming datagrams */ modifier notFrozen(IIsmpHost host) { FrozenStatus state = host.frozen(); if (state == FrozenStatus.Incoming || state == FrozenStatus.All) revert HostFrozen(); _; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IHandler).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Handle incoming consensus messages. These message are accompanied with some cryptographic proof. * If the Host's internal consensus client verifies this proof successfully, * The `StateCommitment` enters the preconfigured challenge period. * @param host - `IsmpHost` * @param proof - consensus proof */ function handleConsensus(IIsmpHost host, bytes calldata proof) external notFrozen(host) { uint256 delay = block.timestamp - host.consensusUpdateTime(); if (delay >= host.unStakingPeriod()) revert ConsensusClientExpired(); (bytes memory verifiedState, IntermediateState memory intermediate) = IConsensusClient(host.consensusClient()) .verifyConsensus(host.consensusState(), proof); host.storeConsensusState(verifiedState); // check that we know this state machine and it's a new update uint256 latestHeight = host.latestStateMachineHeight(intermediate.stateMachineId); if (latestHeight != 0 && intermediate.height > latestHeight) { StateMachineHeight memory stateMachineHeight = StateMachineHeight({ stateMachineId: intermediate.stateMachineId, height: intermediate.height }); host.storeStateMachineCommitment(stateMachineHeight, intermediate.commitment); } } /** * @dev Checks the provided requests and their proofs, before dispatching them to their relevant destination modules * @param host - `IsmpHost` * @param request - batch post requests */ function handlePostRequests(IIsmpHost host, PostRequestMessage calldata request) external notFrozen(host) { uint256 timestamp = block.timestamp; uint256 delay = timestamp - host.stateMachineCommitmentUpdateTime(request.proof.height); uint256 challengePeriod = host.challengePeriod(); if (challengePeriod != 0 && challengePeriod > delay) revert ChallengePeriodNotElapsed(); uint256 requestsLen = request.requests.length; MmrLeaf[] memory leaves = new MmrLeaf[](requestsLen); for (uint256 i = 0; i < requestsLen; ++i) { PostRequestLeaf memory leaf = request.requests[i]; // check destination if (!leaf.request.dest.equals(host.host())) revert InvalidMessageDestination(); // check time-out if (timestamp >= leaf.request.timeout()) revert MessageTimedOut(); // duplicate request? bytes32 commitment = leaf.request.hash(); if (host.requestReceipts(commitment) != address(0)) revert DuplicateMessage(); leaves[i] = MmrLeaf(leaf.kIndex, leaf.index, commitment); } bytes32 root = host.stateMachineCommitment(request.proof.height).overlayRoot; if (root == bytes32(0)) revert StateCommitmentNotFound(); if (!MerkleMountainRange.VerifyProof(root, request.proof.multiproof, leaves, request.proof.leafCount)) { revert InvalidProof(); } for (uint256 i = 0; i < requestsLen; ++i) { PostRequestLeaf memory leaf = request.requests[i]; host.dispatchIncoming(leaf.request, _msgSender()); } } /** * @dev Checks the provided responses and their proofs, before dispatching them to their relevant destination modules * @param host - `IsmpHost` * @param response - batch post responses */ function handlePostResponses(IIsmpHost host, PostResponseMessage calldata response) external notFrozen(host) { uint256 timestamp = block.timestamp; uint256 delay = timestamp - host.stateMachineCommitmentUpdateTime(response.proof.height); uint256 challengePeriod = host.challengePeriod(); if (challengePeriod != 0 && challengePeriod > delay) revert ChallengePeriodNotElapsed(); uint256 responsesLength = response.responses.length; MmrLeaf[] memory leaves = new MmrLeaf[](responsesLength); for (uint256 i = 0; i < responsesLength; ++i) { PostResponseLeaf memory leaf = response.responses[i]; // check time-out if (timestamp >= leaf.response.timeout()) revert MessageTimedOut(); // known request? also serves as a source check bytes32 requestCommitment = leaf.response.request.hash(); FeeMetadata memory meta = host.requestCommitments(requestCommitment); if (meta.sender == address(0)) revert InvalidProof(); // duplicate response? if (host.responseReceipts(leaf.response.hash()).relayer != address(0)) revert DuplicateMessage(); leaves[i] = MmrLeaf(leaf.kIndex, leaf.index, leaf.response.hash()); } bytes32 root = host.stateMachineCommitment(response.proof.height).overlayRoot; if (root == bytes32(0)) revert StateCommitmentNotFound(); if (!MerkleMountainRange.VerifyProof(root, response.proof.multiproof, leaves, response.proof.leafCount)) { revert InvalidProof(); } for (uint256 i = 0; i < responsesLength; ++i) { PostResponseLeaf memory leaf = response.responses[i]; host.dispatchIncoming(leaf.response, _msgSender()); } } /** * @dev Checks the provided timed-out requests and their proofs, before dispatching them to their relevant destination modules * @param host - IsmpHost * @param message - batch post request timeouts */ function handlePostRequestTimeouts( IIsmpHost host, PostRequestTimeoutMessage calldata message ) external notFrozen(host) { uint256 delay = block.timestamp - host.stateMachineCommitmentUpdateTime(message.height); uint256 challengePeriod = host.challengePeriod(); if (challengePeriod != 0 && challengePeriod > delay) revert ChallengePeriodNotElapsed(); // fetch the state commitment StateCommitment memory state = host.stateMachineCommitment(message.height); if (state.stateRoot == bytes32(0)) revert StateCommitmentNotFound(); uint256 timeoutsLength = message.timeouts.length; for (uint256 i = 0; i < timeoutsLength; ++i) { PostRequest memory request = message.timeouts[i]; // timed-out? if (request.timeout() > state.timestamp) revert MessageNotTimedOut(); // known request? also serves as source check bytes32 requestCommitment = request.hash(); FeeMetadata memory meta = host.requestCommitments(requestCommitment); if (meta.sender == address(0)) revert UnknownMessage(); bytes[] memory keys = new bytes[](1); keys[i] = bytes.concat(REQUEST_RECEIPTS_STORAGE_PREFIX, bytes.concat(requestCommitment)); // verify state trie non-membership proofs StorageValue memory entry = MerklePatricia.VerifySubstrateProof(state.stateRoot, message.proof, keys)[0]; if (entry.value.length != 0) revert InvalidProof(); host.dispatchTimeOut(request, meta, requestCommitment); } } /** * @dev Check the provided timeouts and their proofs before dispatching them to their relevant modules * @param host - Ismp host * @param message - batch post response timeouts */ function handlePostResponseTimeouts( IIsmpHost host, PostResponseTimeoutMessage calldata message ) external notFrozen(host) { uint256 delay = block.timestamp - host.stateMachineCommitmentUpdateTime(message.height); uint256 challengePeriod = host.challengePeriod(); if (challengePeriod != 0 && challengePeriod > delay) revert ChallengePeriodNotElapsed(); // fetch the state commitment StateCommitment memory state = host.stateMachineCommitment(message.height); if (state.stateRoot == bytes32(0)) revert StateCommitmentNotFound(); uint256 timeoutsLength = message.timeouts.length; for (uint256 i = 0; i < timeoutsLength; ++i) { PostResponse memory response = message.timeouts[i]; // timed-out? if (response.timeout() > state.timestamp) revert MessageNotTimedOut(); // known response? also serves as source check bytes32 responseCommitment = response.hash(); FeeMetadata memory meta = host.responseCommitments(responseCommitment); if (meta.sender == address(0)) revert UnknownMessage(); bytes[] memory keys = new bytes[](1); keys[i] = bytes.concat(RESPONSE_RECEIPTS_STORAGE_PREFIX, bytes.concat(responseCommitment)); // verify state trie non-membership proofs StorageValue memory entry = MerklePatricia.VerifySubstrateProof(state.stateRoot, message.proof, keys)[0]; if (entry.value.length != 0) revert InvalidProof(); host.dispatchTimeOut(response, meta, responseCommitment); } } /** * @dev check response proofs, message delay and timeouts, then dispatch get responses to modules * @param host - Ismp host * @param message - batch get responses */ function handleGetResponses(IIsmpHost host, GetResponseMessage calldata message) external notFrozen(host) { uint256 timestamp = block.timestamp; uint256 delay = timestamp - host.stateMachineCommitmentUpdateTime(message.height); uint256 challengePeriod = host.challengePeriod(); if (challengePeriod != 0 && challengePeriod > delay) revert ChallengePeriodNotElapsed(); bytes32 root = host.stateMachineCommitment(message.height).stateRoot; if (root == bytes32(0)) revert StateCommitmentNotFound(); uint256 responsesLength = message.requests.length; bytes[] memory proof = message.proof; for (uint256 i = 0; i < responsesLength; ++i) { GetRequest memory request = message.requests[i]; // timed-out? if (timestamp >= request.timeout()) revert MessageTimedOut(); // known request? also serves as source check bytes32 requestCommitment = request.hash(); FeeMetadata memory meta = host.requestCommitments(requestCommitment); if (meta.sender == address(0)) revert UnknownMessage(); // duplicate response? if (host.responseReceipts(requestCommitment).relayer != address(0)) revert DuplicateMessage(); StorageValue[] memory values = MerklePatricia.ReadChildProofCheck( root, proof, request.keys, bytes.concat(requestCommitment) ); GetResponse memory response = GetResponse({request: request, values: values}); host.dispatchIncoming(response, _msgSender()); } } /** * @dev Check the provided Get request timeouts, then dispatch to modules * @param host - Ismp host * @param message - batch get request timeouts */ function handleGetRequestTimeouts(IIsmpHost host, GetTimeoutMessage calldata message) external notFrozen(host) { uint256 timeoutsLength = message.timeouts.length; uint256 timestamp = block.timestamp; for (uint256 i = 0; i < timeoutsLength; ++i) { GetRequest memory request = message.timeouts[i]; bytes32 requestCommitment = request.hash(); FeeMetadata memory meta = host.requestCommitments(requestCommitment); if (meta.sender == address(0)) revert InvalidProof(); if (request.timeout() > timestamp) revert MessageNotTimedOut(); host.dispatchTimeOut(request, meta, requestCommitment); } } }
// SPDX-License-Identifier: Apache2 pragma solidity 0.8.17; import "openzeppelin/utils/math/Math.sol"; import "./MerkleMultiProof.sol"; import "./Types.sol"; /** * @title A Merkle Mountain Range proof library * @author Polytope Labs * @notice Use this library to verify the leaves of a merkle mountain range tree * @dev refer to research for more info. https://research.polytope.technology/merkle-mountain-range-multi-proofs */ library MerkleMountainRange { /// @notice Verify that merkle proof is accurate /// @notice This calls CalculateRoot(...) under the hood /// @param root hash of the Merkle's root node /// @param proof a list of nodes required for the proof to be verified /// @param leaves a list of mmr leaves to prove /// @return boolean if the calculated root matches the provided root node function VerifyProof(bytes32 root, bytes32[] memory proof, MmrLeaf[] memory leaves, uint256 mmrSize) internal pure returns (bool) { return root == CalculateRoot(proof, leaves, mmrSize); } /// @notice Calculate merkle root /// @notice this method allows computing the root hash of a merkle tree using Merkle Mountain Range /// @param proof A list of the merkle nodes that are needed to re-calculate root node. /// @param leaves a list of mmr leaves to prove /// @param leafCount the size of the merkle tree /// @return bytes32 hash of the computed root node function CalculateRoot(bytes32[] memory proof, MmrLeaf[] memory leaves, uint256 leafCount) internal pure returns (bytes32) { // special handle the only 1 leaf MMR if (leafCount == 1 && leaves.length == 1 && leaves[0].leaf_index == 0) { return leaves[0].hash; } uint256[] memory subtrees = subtreeHeights(leafCount); uint256 length = subtrees.length; Iterator memory peakRoots = Iterator(0, new bytes32[](length)); Iterator memory proofIter = Iterator(0, proof); uint256 current_subtree; for (uint256 p; p < length;) { uint256 height = subtrees[p]; current_subtree += 2 ** height; MmrLeaf[] memory subtreeLeaves = new MmrLeaf[](0); if (leaves.length > 0) { (subtreeLeaves, leaves) = leavesForSubtree(leaves, current_subtree); } if (subtreeLeaves.length == 0) { if (proofIter.data.length == proofIter.offset) { break; } else { push(peakRoots, next(proofIter)); } } else if (subtreeLeaves.length == 1 && height == 0) { push(peakRoots, subtreeLeaves[0].hash); } else { push(peakRoots, CalculateSubtreeRoot(subtreeLeaves, proofIter, height)); } unchecked { ++p; } } unchecked { peakRoots.offset--; } while (peakRoots.offset != 0) { bytes32 right = previous(peakRoots); bytes32 left = previous(peakRoots); unchecked { ++peakRoots.offset; } peakRoots.data[peakRoots.offset] = keccak256(abi.encodePacked(right, left)); } return peakRoots.data[0]; } function subtreeHeights(uint256 leavesLength) internal pure returns (uint256[] memory) { uint256 maxSubtrees = 64; uint256[] memory indices = new uint256[](maxSubtrees); uint256 i; uint256 current = leavesLength; for (; i < maxSubtrees;) { if (current == 0) { break; } uint256 log = Math.log2(current); indices[i] = log; current = current - 2 ** log; unchecked { ++i; } } // resize array?, sigh solidity. uint256 excess = maxSubtrees - i; assembly { mstore(indices, sub(mload(indices), excess)) } return indices; } /// @notice calculate root hash of a subtree of the merkle mountain /// @param peakLeaves a list of nodes to provide proof for /// @param proofIter a list of node hashes to traverse to compute the peak root hash /// @param height Height of the subtree /// @return peakRoot a tuple containing the peak root hash, and the peak root position in the merkle function CalculateSubtreeRoot(MmrLeaf[] memory peakLeaves, Iterator memory proofIter, uint256 height) internal pure returns (bytes32) { uint256[] memory current_layer; Node[] memory leaves; (leaves, current_layer) = mmrLeafToNode(peakLeaves); Node[][] memory layers = new Node[][](height); for (uint256 i; i < height;) { uint256 nodelength = 2 ** (height - i); if (current_layer.length == nodelength) { break; } uint256[] memory siblings = siblingIndices(current_layer); uint256[] memory diff = difference(siblings, current_layer); uint256 length = diff.length; layers[i] = new Node[](length); for (uint256 j; j < length;) { layers[i][j] = Node(diff[j], next(proofIter)); unchecked { ++j; } } current_layer = parentIndices(siblings); unchecked { ++i; } } return MerkleMultiProof.CalculateRoot(layers, leaves); } /** * @notice difference ensures all nodes have a sibling. * @dev left and right are designed to be equal length array * @param left a list of hashes * @param right a list of hashes to compare * @return uint256[] a new array with difference */ function difference(uint256[] memory left, uint256[] memory right) internal pure returns (uint256[] memory) { uint256 length = left.length; uint256 rightLength = right.length; uint256[] memory diff = new uint256[](length); uint256 d; for (uint256 i; i < length;) { bool found; for (uint256 j; j < rightLength;) { if (left[i] == right[j]) { found = true; break; } unchecked { ++j; } } if (!found) { diff[d] = left[i]; d++; } unchecked { ++i; } } // resize array?, sigh solidity. uint256 excess = length - d; assembly { mstore(diff, sub(mload(diff), excess)) } return diff; } /** * @dev calculates the index of each sibling index of the proof nodes * @dev proof nodes are the nodes that will be traversed to estimate the root hash * @param indices a list of proof nodes indices * @return uint256[] a list of sibling indices */ function siblingIndices(uint256[] memory indices) internal pure returns (uint256[] memory) { uint256 length = indices.length; uint256[] memory siblings = new uint256[](length); for (uint256 i; i < length;) { uint256 index = indices[i]; if (index == 0) { siblings[i] = index + 1; } else if (index % 2 == 0) { siblings[i] = index + 1; } else { siblings[i] = index - 1; } unchecked { ++i; } } return siblings; } /** * @notice Compute Parent Indices * @dev Used internally to calculate the indices of the parent nodes of the provided proof nodes * @param indices a list of indices of proof nodes in a merkle mountain * @return uint256[] a list of parent indices for each index provided */ function parentIndices(uint256[] memory indices) internal pure returns (uint256[] memory) { uint256 length = indices.length; uint256[] memory parents = new uint256[](length); uint256 k; for (uint256 i; i < length; i++) { uint256 index = indices[i] / 2; if (k > 0 && parents[k - 1] == index) { continue; } parents[k] = index; unchecked { ++k; } } // resize array?, sigh solidity. uint256 excess = length - k; assembly { mstore(parents, sub(mload(parents), excess)) } return parents; } /** * @notice Convert Merkle mountain Leaf to a Merkle Node * @param leaves list of merkle mountain range leaf * @return A tuple with the list of merkle nodes and the list of nodes at 0 and 1 respectively */ function mmrLeafToNode(MmrLeaf[] memory leaves) internal pure returns (Node[] memory, uint256[] memory) { uint256 i; uint256 length = leaves.length; Node[] memory nodes = new Node[](length); uint256[] memory indices = new uint256[](length); while (i < length) { nodes[i] = Node(leaves[i].k_index, leaves[i].hash); indices[i] = leaves[i].k_index; ++i; } return (nodes, indices); } /** * @notice Get a mountain peak's leaves * @notice this splits the leaves into either side of the peak [left & right] * @param leaves a list of mountain merkle leaves, for a subtree * @param leafIndex the index of the leaf of the next subtree * @return A tuple of 2 arrays of mountain merkle leaves. Index 1 and 2 represent left and right of the peak respectively */ function leavesForSubtree(MmrLeaf[] memory leaves, uint256 leafIndex) internal pure returns (MmrLeaf[] memory, MmrLeaf[] memory) { uint256 p; uint256 length = leaves.length; for (; p < length; p++) { if (leafIndex <= leaves[p].leaf_index) { break; } } uint256 len = p == 0 ? 0 : p; MmrLeaf[] memory left = new MmrLeaf[](len); MmrLeaf[] memory right = new MmrLeaf[](length - len); uint256 i; uint256 leftLength = left.length; while (i < leftLength) { left[i] = leaves[i]; ++i; } uint256 j; while (i < length) { right[j] = leaves[i]; ++i; ++j; } return (left, right); } function push(Iterator memory iterator, bytes32 data) internal pure { iterator.data[iterator.offset] = data; unchecked { ++iterator.offset; } } function next(Iterator memory iterator) internal pure returns (bytes32) { bytes32 data = iterator.data[iterator.offset]; unchecked { ++iterator.offset; } return data; } function previous(Iterator memory iterator) internal pure returns (bytes32) { bytes32 data = iterator.data[iterator.offset]; unchecked { --iterator.offset; } return data; } }
pragma solidity 0.8.17; import "./trie/Node.sol"; import "./trie/Option.sol"; import "./trie/NibbleSlice.sol"; import "./trie/TrieDB.sol"; import "./trie/substrate/SubstrateTrieDB.sol"; import "./trie/ethereum/EthereumTrieDB.sol"; import "./Types.sol"; // SPDX-License-Identifier: Apache2 /** * @title A Merkle Patricia library * @author Polytope Labs * @dev Use this library to verify merkle patricia proofs * @dev refer to research for more info. https://research.polytope.technology/state-(machine)-proofs */ library MerklePatricia { /** * @notice Verifies substrate specific merkle patricia proofs. * @param root hash of the merkle patricia trie * @param proof a list of proof nodes * @param keys a list of keys to verify * @return bytes[] a list of values corresponding to the supplied keys. */ function VerifySubstrateProof(bytes32 root, bytes[] memory proof, bytes[] memory keys) public pure returns (StorageValue[] memory) { StorageValue[] memory values = new StorageValue[](keys.length); TrieNode[] memory nodes = new TrieNode[](proof.length); for (uint256 i = 0; i < proof.length; i++) { nodes[i] = TrieNode(keccak256(proof[i]), proof[i]); } for (uint256 i = 0; i < keys.length; i++) { values[i].key = keys[i]; NibbleSlice memory keyNibbles = NibbleSlice(keys[i], 0); NodeKind memory node = SubstrateTrieDB.decodeNodeKind(TrieDB.get(nodes, root)); // This loop is unbounded so that an adversary cannot insert a deeply nested key in the trie // and successfully convince us of it's non-existence, if we consume the block gas limit while // traversing the trie, then the transaction should revert. for (uint256 j = 1; j > 0; j++) { NodeHandle memory nextNode; if (TrieDB.isLeaf(node)) { Leaf memory leaf = SubstrateTrieDB.decodeLeaf(node); if (NibbleSliceOps.eq(leaf.key, keyNibbles)) { values[i].value = TrieDB.load(nodes, leaf.value); } break; } else if (TrieDB.isNibbledBranch(node)) { NibbledBranch memory nibbled = SubstrateTrieDB.decodeNibbledBranch(node); uint256 nibbledBranchKeyLength = NibbleSliceOps.len(nibbled.key); if (!NibbleSliceOps.startsWith(keyNibbles, nibbled.key)) { break; } if (NibbleSliceOps.len(keyNibbles) == nibbledBranchKeyLength) { if (Option.isSome(nibbled.value)) { values[i].value = TrieDB.load(nodes, nibbled.value.value); } break; } else { uint256 index = NibbleSliceOps.at(keyNibbles, nibbledBranchKeyLength); NodeHandleOption memory handle = nibbled.children[index]; if (Option.isSome(handle)) { keyNibbles = NibbleSliceOps.mid(keyNibbles, nibbledBranchKeyLength + 1); nextNode = handle.value; } else { break; } } } else if (TrieDB.isEmpty(node)) { break; } node = SubstrateTrieDB.decodeNodeKind(TrieDB.load(nodes, nextNode)); } } return values; } /** * @notice Verify child trie keys * @dev substrate specific method in order to verify keys in the child trie. * @param root hash of the merkle root * @param proof a list of proof nodes * @param keys a list of keys to verify * @param childInfo data that can be used to compute the root of the child trie * @return bytes[], a list of values corresponding to the supplied keys. */ function ReadChildProofCheck(bytes32 root, bytes[] memory proof, bytes[] memory keys, bytes memory childInfo) public pure returns (StorageValue[] memory) { // fetch the child trie root hash; bytes memory prefix = bytes(":child_storage:default:"); bytes memory key = bytes.concat(prefix, childInfo); bytes[] memory _keys = new bytes[](1); _keys[0] = key; StorageValue[] memory values = VerifySubstrateProof(root, proof, _keys); bytes32 childRoot = bytes32(values[0].value); require(childRoot != bytes32(0), "Invalid child trie proof"); return VerifySubstrateProof(childRoot, proof, keys); } /** * @notice Verifies ethereum specific merkle patricia proofs as described by EIP-1188. * @param root hash of the merkle patricia trie * @param proof a list of proof nodes * @param keys a list of keys to verify * @return bytes[] a list of values corresponding to the supplied keys. */ function VerifyEthereumProof(bytes32 root, bytes[] memory proof, bytes[] memory keys) public pure returns (StorageValue[] memory) { StorageValue[] memory values = new StorageValue[](keys.length); TrieNode[] memory nodes = new TrieNode[](proof.length); for (uint256 i = 0; i < proof.length; i++) { nodes[i] = TrieNode(keccak256(proof[i]), proof[i]); } for (uint256 i = 0; i < keys.length; i++) { values[i].key = keys[i]; NibbleSlice memory keyNibbles = NibbleSlice(keys[i], 0); NodeKind memory node = EthereumTrieDB.decodeNodeKind(TrieDB.get(nodes, root)); // This loop is unbounded so that an adversary cannot insert a deeply nested key in the trie // and successfully convince us of it's non-existence, if we consume the block gas limit while // traversing the trie, then the transaction should revert. for (uint256 j = 1; j > 0; 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)) { values[i].value = TrieDB.load(nodes, leaf.value); } 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 uint256 cutNibble = keyNibbles.offset + NibbleSliceOps.len(extension.key); keyNibbles = NibbleSlice( NibbleSliceOps.bytesSlice(keyNibbles.data, cutNibble / 2), cutNibble % 2 ); 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)) { values[i].value = TrieDB.load(nodes, branch.value.value); } 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 values; } }
pragma solidity 0.8.17; // SPDX-License-Identifier: Apache2 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: UNLICENSED pragma solidity 0.8.17; // The state commiment identifies a commiment to some intermediate state in the state machine. // This contains some metadata about the state machine like it's own timestamp at the time of this commitment. struct StateCommitment { // This timestamp is useful for handling request timeouts. uint256 timestamp; // Overlay trie commitment to all ismp requests & response. bytes32 overlayRoot; // State trie commitment at the given block height bytes32 stateRoot; } // Identifies some state machine height. We allow for a state machine identifier here // as some consensus clients may track multiple, concurrent state machines. struct StateMachineHeight { // the state machine identifier uint256 stateMachineId; // height of this state machine uint256 height; } // An intermediate state in the series of state transitions undergone by a given state machine. struct IntermediateState { // the state machine identifier uint256 stateMachineId; // height of this state machine uint256 height; // state commitment StateCommitment commitment; } /** * @title The Ismp ConsensusClient * @author Polytope Labs ([email protected]) * * @notice The consensus client interface responsible for the verification of consensus datagrams. * It's internals are opaque to the ISMP framework allowing it to evolve as needed. */ interface IConsensusClient { // @dev Given some opaque consensus proof, produce the new consensus state and newly finalized intermediate states. function verifyConsensus( bytes memory trustedState, bytes memory proof ) external returns (bytes memory, IntermediateState memory); }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.17; import {StateCommitment, StateMachineHeight} from "./IConsensusClient.sol"; import {IDispatcher} from "./IDispatcher.sol"; import {PostRequest, PostResponse, GetResponse, PostTimeout, GetRequest} from "./Message.sol"; // Some metadata about the request fee struct FeeMetadata { // the relayer fee uint256 fee; // user who initiated the request address sender; } struct ResponseReceipt { // commitment of the response object bytes32 responseCommitment; // address of the relayer responsible for this response delivery address relayer; } // Various frozen states of the IIsmpHost enum FrozenStatus { // Host is operating normally None, // Host is currently disallowing incoming datagrams Incoming, // Host is currently disallowing outgoing messages Outgoing, // All actions have been frozen All } /** * @title The Ismp Host Interface * @author Polytope Labs ([email protected]) * * @notice The Ismp Host interface sits at the core of the interoperable state machine protocol, * It which encapsulates the interfaces required for ISMP datagram handlers and modules. * * @dev The IsmpHost provides the necessary storage interface for the ISMP handlers to process * ISMP messages, the IsmpDispatcher provides the interfaces applications use for dispatching requests * and responses. This host implementation delegates all verification logic to the IHandler contract. * It is only responsible for dispatching incoming & outgoing messages as well as managing * the state of the ISMP protocol. */ interface IIsmpHost is IDispatcher { /** * @return the host admin */ function admin() external returns (address); /** * @return the address of the fee token ERC-20 contract on this state machine */ function feeToken() external view returns (address); /** * @return the per-byte fee for outgoing messages. */ function perByteFee() external view returns (uint256); /** * @return the host state machine id */ function host() external view returns (bytes memory); /** * @return the state machine identifier for the connected hyperbridge instance */ function hyperbridge() external view returns (bytes memory); /** * @return the host timestamp */ function timestamp() external view returns (uint256); /** * @dev Returns the nonce immediately available for requests * @return the `nonce` */ function nonce() external view returns (uint256); /** * @dev Returns the fisherman responsible for vetoing the given state machine height. * @return the `fisherman` address */ function vetoes(uint256 paraId, uint256 height) external view returns (address); /** * @return the `frozen` status */ function frozen() external view returns (FrozenStatus); /** * @dev Returns the address for the Uniswap V2 Router implementation used for swaps * @return routerAddress - The address to the in-use RouterV02 implementation */ function uniswapV2Router() external view returns (address); /** * @dev Returns the fee required for 3rd party applications to access hyperbridge state commitments. * @return the `stateCommitmentFee` */ function stateCommitmentFee() external view returns (uint256); /** * @notice Charges the stateCommitmentFee to 3rd party applications. * If native tokens are provided, will attempt to swap them for the stateCommitmentFee. * If not enough native tokens are supplied, will revert. * * If no native tokens are provided then it will try to collect payment from the calling contract in * the IIsmpHost.feeToken. * * @param height - state machine height * @return the state commitment at `height` */ function stateMachineCommitment(StateMachineHeight memory height) external payable returns (StateCommitment memory); /** * @param height - state machine height * @return the state machine commitment update time at `height` */ function stateMachineCommitmentUpdateTime(StateMachineHeight memory height) external returns (uint256); /** * @return the consensus client contract */ function consensusClient() external view returns (address); /** * @return the last updated time of the consensus client */ function consensusUpdateTime() external view returns (uint256); /** * @return the latest state machine height for the given stateMachineId. If it returns 0, the state machine is unsupported. */ function latestStateMachineHeight(uint256 stateMachineId) external view returns (uint256); /** * @return the state of the consensus client */ function consensusState() external view returns (bytes memory); /** * @dev Check the response status for a given request. * @return `response` status */ function responded(bytes32 commitment) external view returns (bool); /** * @param commitment - commitment to the request * @return relayer address */ function requestReceipts(bytes32 commitment) external view returns (address); /** * @param commitment - commitment to the request of the response * @return response receipt */ function responseReceipts(bytes32 commitment) external view returns (ResponseReceipt memory); /** * @param commitment - commitment to the request * @return existence status of an outgoing request commitment */ function requestCommitments(bytes32 commitment) external view returns (FeeMetadata memory); /** * @param commitment - commitment to the response * @return existence status of an outgoing response commitment */ function responseCommitments(bytes32 commitment) external view returns (FeeMetadata memory); /** * @return the challenge period */ function challengePeriod() external view returns (uint256); /** * @return the unstaking period */ function unStakingPeriod() external view returns (uint256); /** * @dev set the new frozen state of the host, only the admin or handler can call this. * @param newState - the new frozen state */ function setFrozenState(FrozenStatus newState) external; /** * @dev Store an encoded consensus state * @param state new consensus state */ function storeConsensusState(bytes memory state) external; /** * @dev Store the commitment at `state height` * @param height state machine height * @param commitment state commitment */ function storeStateMachineCommitment(StateMachineHeight memory height, StateCommitment memory commitment) external; /** * @dev Delete the state commitment at given state height. */ function deleteStateMachineCommitment(StateMachineHeight memory height, address fisherman) external; /** * @dev Dispatch an incoming request to destination module * @param request - post request */ function dispatchIncoming(PostRequest memory request, address relayer) external; /** * @dev Dispatch an incoming post response to source module * @param response - post response */ function dispatchIncoming(PostResponse memory response, address relayer) external; /** * @dev Dispatch an incoming get response to source module * @param response - get response */ function dispatchIncoming(GetResponse memory response, address relayer) external; /** * @dev Dispatch an incoming get timeout to source module * @param timeout - timed-out get request */ function dispatchTimeOut(GetRequest memory timeout, FeeMetadata memory meta, bytes32 commitment) external; /** * @dev Dispatch an incoming post timeout to source module * @param timeout - timed-out post request */ function dispatchTimeOut(PostRequest memory timeout, FeeMetadata memory meta, bytes32 commitment) external; /** * @dev Dispatch an incoming post response timeout to source module * @param timeout - timed-out post response */ function dispatchTimeOut(PostResponse memory timeout, FeeMetadata memory meta, bytes32 commitment) external; }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.17; import {IIsmpHost} from "./IIsmpHost.sol"; import {PostRequestMessage, PostResponseMessage, GetResponseMessage, PostRequestTimeoutMessage, PostResponseTimeoutMessage, GetTimeoutMessage} from "./Message.sol"; /* * @title The Ismp Handler * @author Polytope Labs ([email protected]) * * @notice The IHandler interface serves as the entry point for ISMP datagrams, i.e consensus, requests & response messages. */ interface IHandler { /** * @dev Handle an incoming consensus message. This uses the IConsensusClient contract registered on the host to perform the consensus message verification. * @param host - Ismp host * @param proof - consensus proof */ function handleConsensus(IIsmpHost host, bytes memory proof) external; /** * @dev Handles incoming POST requests, check request proofs, message delay and timeouts, then dispatch POST requests to the apropriate contracts. * @param host - Ismp host * @param request - batch post requests */ function handlePostRequests(IIsmpHost host, PostRequestMessage memory request) external; /** * @dev Handles incoming POST responses, check response proofs, message delay and timeouts, then dispatch POST responses to the apropriate contracts. * @param host - Ismp host * @param response - batch post responses */ function handlePostResponses(IIsmpHost host, PostResponseMessage memory response) external; /** * @dev check response proofs, message delay and timeouts, then dispatch get responses to modules * @param host - Ismp host * @param message - batch get responses */ function handleGetResponses(IIsmpHost host, GetResponseMessage memory message) external; /** * @dev check timeout proofs then dispatch to modules * @param host - Ismp host * @param message - batch post request timeouts */ function handlePostRequestTimeouts(IIsmpHost host, PostRequestTimeoutMessage memory message) external; /** * @dev check timeout proofs then dispatch to modules * @param host - Ismp host * @param message - batch post response timeouts */ function handlePostResponseTimeouts(IIsmpHost host, PostResponseTimeoutMessage memory message) external; /** * @dev dispatch to modules * @param host - Ismp host * @param message - batch get request timeouts */ function handleGetRequestTimeouts(IIsmpHost host, GetTimeoutMessage memory message) external; }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.17; import {StateMachineHeight} from "./IConsensusClient.sol"; import {StorageValue} from "@polytope-labs/solidity-merkle-trees/Types.sol"; struct PostRequest { // the source state machine of this request bytes source; // the destination state machine of this request bytes dest; // request nonce uint64 nonce; // Module Id of this request origin bytes from; // destination module id bytes to; // timestamp by which this request times out. uint64 timeoutTimestamp; // request body bytes body; } struct GetRequest { // the source state machine of this request bytes source; // the destination state machine of this request bytes dest; // request nonce uint64 nonce; // Module Id of this request origin address from; // timestamp by which this request times out. uint64 timeoutTimestamp; // Storage keys to read. bytes[] keys; // height at which to read destination state machine uint64 height; } struct GetResponse { // The request that initiated this response GetRequest request; // storage values for get response StorageValue[] values; } struct PostResponse { // The request that initiated this response PostRequest request; // bytes for post response bytes response; // timestamp by which this response times out. uint64 timeoutTimestamp; } // A post request as a leaf in a merkle tree struct PostRequestLeaf { // The request PostRequest request; // It's index in the mmr leaves uint256 index; // it's k-index uint256 kIndex; } // A post response as a leaf in a merkle tree struct PostResponseLeaf { // The response PostResponse response; // It's index in the mmr leaves uint256 index; // it's k-index uint256 kIndex; } // A merkle mountain range proof. struct Proof { // height of the state machine StateMachineHeight height; // the multi-proof bytes32[] multiproof; // The total number of leaves in the mmr for this proof. uint256 leafCount; } // A message for handling incoming requests struct PostRequestMessage { // proof for the requests Proof proof; // the requests, contained in a merkle tree leaf PostRequestLeaf[] requests; } // A message for handling incoming GET responses struct GetResponseMessage { // the state (merkle-patricia) proof of the get request keys bytes[] proof; // the height of the state machine proof StateMachineHeight height; // The requests that initiated this response GetRequest[] requests; } struct GetTimeoutMessage { // requests which have timed-out GetRequest[] timeouts; } struct PostTimeout { PostRequest request; } struct PostRequestTimeoutMessage { // requests which have timed-out PostRequest[] timeouts; // the height of the state machine proof StateMachineHeight height; // non-membership proof of the requests bytes[] proof; } struct PostResponseTimeoutMessage { // responses which have timed-out PostResponse[] timeouts; // the height of the state machine proof StateMachineHeight height; // non-membership proof of the requests bytes[] proof; } // A message for handling incoming responses struct PostResponseMessage { // proof for the responses Proof proof; // the responses, contained in a merkle tree leaf PostResponseLeaf[] responses; } library Message { function timeout(PostRequest memory req) internal pure returns (uint64) { if (req.timeoutTimestamp == 0) { return type(uint64).max; } else { return req.timeoutTimestamp; } } function timeout(GetRequest memory req) internal pure returns (uint64) { if (req.timeoutTimestamp == 0) { return type(uint64).max; } else { return req.timeoutTimestamp; } } function timeout(PostResponse memory res) internal pure returns (uint64) { if (res.timeoutTimestamp == 0) { return type(uint64).max; } else { return res.timeoutTimestamp; } } function encodeRequest(PostRequest memory req) internal pure returns (bytes memory) { return abi.encodePacked(req.source, req.dest, req.nonce, req.timeoutTimestamp, req.from, req.to, req.body); } function hash(PostResponse memory res) internal pure returns (bytes32) { return keccak256(bytes.concat(encodeRequest(res.request), abi.encodePacked(res.response, res.timeoutTimestamp))); } function hash(PostRequest memory req) internal pure returns (bytes32) { return keccak256(encodeRequest(req)); } function hash(GetRequest memory req) internal pure returns (bytes32) { bytes memory keysEncoding = bytes(""); uint256 len = req.keys.length; for (uint256 i = 0; i < len; i++) { keysEncoding = bytes.concat(keysEncoding, req.keys[i]); } return keccak256( abi.encodePacked( req.source, req.dest, req.nonce, req.height, req.timeoutTimestamp, abi.encodePacked(req.from), keysEncoding ) ); } function hash(GetResponse memory res) internal pure returns (bytes32) { return hash(res.request); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with 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; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv( uint256 x, uint256 y, uint256 denominator, Rounding rounding ) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10**64) { value /= 10**64; result += 64; } if (value >= 10**32) { value /= 10**32; result += 32; } if (value >= 10**16) { value /= 10**16; result += 16; } if (value >= 10**8) { value /= 10**8; result += 8; } if (value >= 10**4) { value /= 10**4; result += 4; } if (value >= 10**2) { value /= 10**2; result += 2; } if (value >= 10**1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0); } } }
// SPDX-License-Identifier: Apache2 pragma solidity 0.8.17; import "openzeppelin/utils/math/Math.sol"; import "./Types.sol"; /** * @title A Merkle Multi proof library * @author Polytope Labs * @dev Use this library to verify merkle tree leaves using merkle multi proofs * @dev refer to research for more info. https://research.polytope.technology/merkle-multi-proofs */ library MerkleMultiProof { /** * @notice Verify a Merkle Multi Proof * @param root hash of the root node of the merkle tree * @param proof A list of the merkle nodes along with their k-indices that are needed to re-calculate root node. * @param leaves A list of the leaves along with their k-indices to prove * @return boolean if the calculated root matches the provides root node */ function VerifyProof(bytes32 root, Node[][] memory proof, Node[] memory leaves) internal pure returns (bool) { return root == CalculateRoot(proof, leaves); } /** * @notice Verify a Merkle Multi Proof whose internal nodes are sorted * @param root hash of the root node of the merkle tree * @param proof A list of the merkle nodes along with their k-indices that are needed to re-calculate root node. * @param leaves A list of the leaves along with their k-indices to prove * @return boolean if the calculated root matches the provides root node */ function VerifyProofSorted(bytes32 root, Node[][] memory proof, Node[] memory leaves) internal pure returns (bool) { return root == CalculateRootSorted(proof, leaves); } /// @notice Calculate the hash of the root node /// @dev Use this function to calculate the hash of the root node /// @param proof A list of the merkle nodes along with their k-indices that are needed to re-calculate root node. /// @param leaves A list of the leaves along with their k-indices to prove /// @return Hash of root node, value is a bytes32 type function CalculateRoot(Node[][] memory proof, Node[] memory leaves) internal pure returns (bytes32) { // holds the output from hashing a previous layer Node[] memory next_layer = new Node[](0); // merge leaves proof[0] = mergeSort(leaves, proof[0]); uint256 proof_length = proof.length; for (uint256 height = 0; height < proof_length; height++) { Node[] memory current_layer = new Node[](0); if (next_layer.length == 0) { current_layer = proof[height]; } else { current_layer = mergeSort(proof[height], next_layer); } next_layer = new Node[](div_ceil(current_layer.length, 2)); uint256 p = 0; uint256 current_layer_length = current_layer.length; for (uint256 index = 0; index < current_layer_length; index += 2) { if (index + 1 >= current_layer_length) { Node memory node = current_layer[index]; node.k_index = div_floor(current_layer[index].k_index, 2); next_layer[p] = node; } else { Node memory node; node.k_index = div_floor(current_layer[index].k_index, 2); node.node = _optimizedHash(current_layer[index].node, current_layer[index + 1].node); next_layer[p] = node; unchecked { p++; } } } } // we should have arrived at the root node require(next_layer.length == 1); return next_layer[0].node; } /// @notice Calculate the hash of the root node using a sorted node approach. /// @dev Use this function to calculate the hash of the root node /// @param proof A list of the merkle nodes that are needed to re-calculate root node. /// @param leaves A list of the leaves to prove /// @return Hash of root node, value is a bytes32 type function CalculateRootSorted(Node[][] memory proof, Node[] memory leaves) internal pure returns (bytes32) { // holds the output from hashing a previous layer Node[] memory next_layer = new Node[](0); // merge leaves proof[0] = mergeSort(leaves, proof[0]); uint256 proof_length = proof.length; for (uint256 height = 0; height < proof_length; height++) { Node[] memory current_layer = new Node[](0); if (next_layer.length == 0) { current_layer = proof[height]; } else { current_layer = mergeSort(proof[height], next_layer); } uint256 current_layer_length = current_layer.length; uint256 p = 0; next_layer = new Node[](div_ceil(current_layer_length, 2)); for (uint256 index = 0; index < current_layer_length; index += 2) { if (index + 1 >= current_layer_length) { Node memory node = current_layer[index]; node.k_index = div_floor(current_layer[index].k_index, 2); next_layer[p] = node; } else { Node memory node; bytes32 a = current_layer[index].node; bytes32 b = current_layer[index + 1].node; if (a < b) { node.node = _optimizedHash(a, b); } else { node.node = _optimizedHash(b, a); } node.k_index = div_floor(current_layer[index].k_index, 2); next_layer[p] = node; unchecked { p++; } } } } // we should have arrived at the root node require(next_layer.length == 1); return next_layer[0].node; } function div_floor(uint256 x, uint256 y) internal pure returns (uint256) { return x / y; } function div_ceil(uint256 x, uint256 y) internal pure returns (uint256) { uint256 result = x / y; if (x % y != 0) { unchecked { result += 1; } } return result; } /// @notice an internal function to merge two arrays and sort them at the same time. /// @dev compares the k-index of each node and sort in increasing order /// @param arr1 leftmost index in arr /// @param arr2 highest index in arr function mergeSort(Node[] memory arr1, Node[] memory arr2) internal pure returns (Node[] memory) { // merge the two arrays uint256 i = 0; uint256 j = 0; uint256 k = 0; uint256 arr1_length = arr1.length; uint256 arr2_length = arr2.length; uint256 out_len = arr1_length + arr2_length; Node[] memory out = new Node[](out_len); while (i < arr1_length && j < arr2_length) { if (arr1[i].k_index < arr2[j].k_index) { out[k] = arr1[i]; unchecked { i++; k++; } } else { out[k] = arr2[j]; unchecked { j++; k++; } } } while (i < arr1_length) { out[k] = arr1[i]; unchecked { i++; k++; } } while (j < arr2_length) { out[k] = arr2[j]; unchecked { j++; k++; } } return out; } /// @notice compute the keccak256 hash of two nodes /// @param node1 hash of one of the two nodes /// @param node2 hash of the other of the two nodes function _optimizedHash(bytes32 node1, bytes32 node2) internal pure returns (bytes32 hash) { assembly { // use EVM scratch space, its memory safe mstore(0x0, node1) mstore(0x20, node2) hash := keccak256(0x0, 0x40) } } /// @notice compute the height of the tree whose total number of leaves is given, it accounts for unbalanced trees. /// @param leavesCount number of leaves in the tree /// @return height of the tree function TreeHeight(uint256 leavesCount) internal pure returns (uint256) { uint256 height = Math.log2(leavesCount, Math.Rounding.Up); if (!isPowerOfTwo(leavesCount)) { unchecked { height++; } } return height; } function isPowerOfTwo(uint256 x) internal pure returns (bool) { if (x == 0) { return false; } return (x & (x - 1)) == 0; } }
pragma solidity 0.8.17; // SPDX-License-Identifier: Apache2 // Outcome of a successfully verified merkle-patricia proof struct StorageValue { // the storage key bytes key; // the encoded value bytes value; } /// @title A representation of a Merkle tree node struct Node { // Distance of the node to the leftmost node uint256 k_index; // A hash of the node itself bytes32 node; } /// @title A representation of a MerkleMountainRange leaf struct MmrLeaf { // the leftmost index of a node uint256 k_index; // The position in the tree uint256 leaf_index; // The hash of the position in the tree bytes32 hash; } struct Iterator { uint256 offset; bytes32[] data; }
pragma solidity 0.8.17; // SPDX-License-Identifier: Apache2 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; }
pragma solidity 0.8.17; import "./Node.sol"; // SPDX-License-Identifier: Apache2 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; } }
pragma solidity 0.8.17; // SPDX-License-Identifier: Apache2 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.17; 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; } }
pragma solidity 0.8.17; import "../Node.sol"; import "../Bytes.sol"; import {NibbleSliceOps} from "../NibbleSlice.sol"; import {ScaleCodec} from "./ScaleCodec.sol"; import "openzeppelin/utils/Strings.sol"; // SPDX-License-Identifier: Apache2 library SubstrateTrieDB { uint8 public constant FIRST_PREFIX = 0x00 << 6; uint8 public constant PADDING_BITMASK = 0x0F; uint8 public constant EMPTY_TRIE = FIRST_PREFIX | (0x00 << 4); uint8 public constant LEAF_PREFIX_MASK = 0x01 << 6; uint8 public constant BRANCH_WITH_MASK = 0x03 << 6; uint8 public constant BRANCH_WITHOUT_MASK = 0x02 << 6; uint8 public constant ALT_HASHING_LEAF_PREFIX_MASK = FIRST_PREFIX | (0x01 << 5); uint8 public constant ALT_HASHING_BRANCH_WITH_MASK = FIRST_PREFIX | (0x01 << 4); uint8 public constant NIBBLE_PER_BYTE = 2; uint256 public constant NIBBLE_SIZE_BOUND = uint256(type(uint16).max); uint256 public constant BITMAP_LENGTH = 2; uint256 public constant HASH_lENGTH = 32; function decodeNodeKind(bytes memory encoded) internal pure returns (NodeKind memory) { NodeKind memory node; ByteSlice memory input = ByteSlice(encoded, 0); uint8 i = Bytes.readByte(input); if (i == EMPTY_TRIE) { node.isEmpty = true; return node; } uint8 mask = i & (0x03 << 6); if (mask == LEAF_PREFIX_MASK) { node.nibbleSize = decodeSize(i, input, 2); node.isLeaf = true; } else if (mask == BRANCH_WITH_MASK) { node.nibbleSize = decodeSize(i, input, 2); node.isNibbledValueBranch = true; } else if (mask == BRANCH_WITHOUT_MASK) { node.nibbleSize = decodeSize(i, input, 2); node.isNibbledBranch = true; } else if (mask == EMPTY_TRIE) { if (i & (0x07 << 5) == ALT_HASHING_LEAF_PREFIX_MASK) { node.nibbleSize = decodeSize(i, input, 3); node.isHashedLeaf = true; } else if (i & (0x0F << 4) == ALT_HASHING_BRANCH_WITH_MASK) { node.nibbleSize = decodeSize(i, input, 4); node.isNibbledHashedValueBranch = true; } else { // do not allow any special encoding revert("Unallowed encoding"); } } node.data = input; return node; } function decodeNibbledBranch(NodeKind memory node) internal pure returns (NibbledBranch memory) { NibbledBranch memory nibbledBranch; ByteSlice memory input = node.data; bool padding = node.nibbleSize % NIBBLE_PER_BYTE != 0; if (padding && (padLeft(uint8(input.data[input.offset])) != 0)) { revert("Bad Format!"); } uint256 nibbleLen = ((node.nibbleSize + (NibbleSliceOps.NIBBLE_PER_BYTE - 1)) / NibbleSliceOps.NIBBLE_PER_BYTE); nibbledBranch.key = NibbleSlice(Bytes.read(input, nibbleLen), node.nibbleSize % NIBBLE_PER_BYTE); bytes memory bitmapBytes = Bytes.read(input, BITMAP_LENGTH); uint16 bitmap = uint16(ScaleCodec.decodeUint256(bitmapBytes)); NodeHandleOption memory valueHandle; if (node.isNibbledHashedValueBranch) { valueHandle.isSome = true; valueHandle.value.isHash = true; valueHandle.value.hash = Bytes.toBytes32(Bytes.read(input, HASH_lENGTH)); } else if (node.isNibbledValueBranch) { uint256 len = ScaleCodec.decodeUintCompact(input); valueHandle.isSome = true; valueHandle.value.isInline = true; valueHandle.value.inLine = Bytes.read(input, len); } nibbledBranch.value = valueHandle; for (uint256 i = 0; i < 16; i++) { NodeHandleOption memory childHandle; if (valueAt(bitmap, i)) { childHandle.isSome = true; uint256 len = ScaleCodec.decodeUintCompact(input); // revert(string.concat("node index: ", Strings.toString(len))); if (len == HASH_lENGTH) { childHandle.value.isHash = true; childHandle.value.hash = Bytes.toBytes32(Bytes.read(input, HASH_lENGTH)); } else { childHandle.value.isInline = true; childHandle.value.inLine = Bytes.read(input, len); } } nibbledBranch.children[i] = childHandle; } return nibbledBranch; } function decodeLeaf(NodeKind memory node) internal pure returns (Leaf memory) { Leaf memory leaf; ByteSlice memory input = node.data; bool padding = node.nibbleSize % NIBBLE_PER_BYTE != 0; if (padding && padLeft(uint8(input.data[input.offset])) != 0) { revert("Bad Format!"); } uint256 nibbleLen = (node.nibbleSize + (NibbleSliceOps.NIBBLE_PER_BYTE - 1)) / NibbleSliceOps.NIBBLE_PER_BYTE; bytes memory nibbleBytes = Bytes.read(input, nibbleLen); leaf.key = NibbleSlice(nibbleBytes, node.nibbleSize % NIBBLE_PER_BYTE); NodeHandle memory handle; if (node.isHashedLeaf) { handle.isHash = true; handle.hash = Bytes.toBytes32(Bytes.read(input, HASH_lENGTH)); } else { uint256 len = ScaleCodec.decodeUintCompact(input); handle.isInline = true; handle.inLine = Bytes.read(input, len); } leaf.value = handle; return leaf; } function decodeSize(uint8 first, ByteSlice memory encoded, uint8 prefixMask) internal pure returns (uint256) { uint8 maxValue = uint8(255 >> prefixMask); uint256 result = uint256(first & maxValue); if (result < maxValue) { return result; } result -= 1; while (result <= NIBBLE_SIZE_BOUND) { uint256 n = uint256(Bytes.readByte(encoded)); if (n < 255) { return result + n + 1; } result += 255; } return NIBBLE_SIZE_BOUND; } function padLeft(uint8 b) internal pure returns (uint8) { return b & ~PADDING_BITMASK; } function valueAt(uint16 bitmap, uint256 i) internal pure returns (bool) { return bitmap & (uint16(1) << uint16(i)) != 0; } }
pragma solidity 0.8.17; import "../Node.sol"; import "../Bytes.sol"; import {NibbleSliceOps} from "../NibbleSlice.sol"; import "./RLPReader.sol"; // SPDX-License-Identifier: Apache2 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) external 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) external 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) external pure returns (Extension memory) { Extension memory extension; RLPReader.RLPItem[] memory decoded = node.data.data.toRlpItem().toList(); bytes memory data = decoded[1].toBytes(); uint8 isOdd = uint8(decoded[0].toBytes()[0] >> 4) & 0x01; //Remove the first byte, which is the prefix and not present in the user provided key extension.key = NibbleSlice(Bytes.substr(decoded[0].toBytes(), (isOdd + 1) % 2), isOdd); extension.node = NodeHandle(true, Bytes.toBytes32(data), false, new bytes(0)); return extension; } function decodeBranch(NodeKind memory node) external 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); } }
pragma solidity 0.8.17; // SPDX-License-Identifier: Apache2 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) } } }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.17; import {StateMachineHeight} from "./IConsensusClient.sol"; import {PostRequest} from "./Message.sol"; // @notice An object for dispatching post requests to the Hyperbridge struct DispatchPost { // bytes representation of the destination state machine bytes dest; // the destination module bytes to; // the request body bytes body; // timeout for this request in seconds uint64 timeout; // the amount put up to be paid to the relayer, // this is charged in `IIsmpHost.feeToken` to `msg.sender` uint256 fee; // who pays for this request? address payer; } // @notice An object for dispatching get requests to the Hyperbridge struct DispatchGet { // bytes representation of the destination state machine bytes dest; // height at which to read the state machine uint64 height; // storage keys to read bytes[] keys; // timeout for this request in seconds uint64 timeout; // Hyperbridge protocol fees for processing this request. uint256 fee; } struct DispatchPostResponse { // The request that initiated this response PostRequest request; // bytes for post response bytes response; // timeout for this response in seconds uint64 timeout; // the amount put up to be paid to the relayer, // this is charged in `IIsmpHost.feeToken` to `msg.sender` uint256 fee; // who pays for this request? address payer; } /* * @title The Ismp Dispatcher * @author Polytope Labs ([email protected]) * * @notice The IHandler interface serves as the entry point for ISMP datagrams, i.e consensus, requests & response messages. */ interface IDispatcher { /** * @dev Dispatch a POST request to Hyperbridge * * @notice Payment for the request can be made with either the native token or the IIsmpHost.feeToken. * If native tokens are supplied, it will perform a swap under the hood using the local uniswap router. * Will revert if enough native tokens are not provided. * * If no native tokens are provided then it will try to collect payment from the calling contract in * the IIsmpHost.feeToken. * * @param request - post request * @return commitment - the request commitment */ function dispatch(DispatchPost memory request) external payable returns (bytes32 commitment); /** * @dev Dispatch a GET request to Hyperbridge * * @notice Payment for the request can be made with either the native token or the IIsmpHost.feeToken. * If native tokens are supplied, it will perform a swap under the hood using the local uniswap router. * Will revert if enough native tokens are not provided. * * If no native tokens are provided then it will try to collect payment from the calling contract in * the IIsmpHost.feeToken. * * @param request - get request * @return commitment - the request commitment */ function dispatch(DispatchGet memory request) external payable returns (bytes32 commitment); /** * @dev Dispatch a POST response to Hyperbridge * * @notice Payment for the request can be made with either the native token or the IIsmpHost.feeToken. * If native tokens are supplied, it will perform a swap under the hood using the local uniswap router. * Will revert if enough native tokens are not provided. * * If no native tokens are provided then it will try to collect payment from the calling contract in * the IIsmpHost.feeToken. * * @param response - post response * @return commitment - the request commitment */ function dispatch(DispatchPostResponse memory response) external payable returns (bytes32 commitment); /** * @dev Increase the relayer fee for a previously dispatched request. * This is provided for use only on pending requests, such that when they timeout, * the user can recover the entire relayer fee. * * @notice Payment can be made with either the native token or the IIsmpHost.feeToken. * If native tokens are supplied, it will perform a swap under the hood using the local uniswap router. * Will revert if enough native tokens are not provided. * * If no native tokens are provided then it will try to collect payment from the calling contract in * the IIsmpHost.feeToken. * * If called on an already delivered request, these funds will be seen as a donation to the hyperbridge protocol. * @param commitment - The request commitment * @param amount - The amount provided in `IIsmpHost.feeToken()` */ function fundRequest(bytes32 commitment, uint256 amount) external payable; /** * @dev Increase the relayer fee for a previously dispatched response. * This is provided for use only on pending responses, such that when they timeout, * the user can recover the entire relayer fee. * * @notice Payment can be made with either the native token or the IIsmpHost.feeToken. * If native tokens are supplied, it will perform a swap under the hood using the local uniswap router. * Will revert if enough native tokens are not provided. * * If no native tokens are provided then it will try to collect payment from the calling contract in * the IIsmpHost.feeToken. * * If called on an already delivered response, these funds will be seen as a donation to the hyperbridge protocol. * @param commitment - The response commitment * @param amount - The amount to be provided in `IIsmpHost.feeToken()` */ function fundResponse(bytes32 commitment, uint256 amount) external payable; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
pragma solidity 0.8.17; // SPDX-License-Identifier: Apache2 import {Bytes, ByteSlice} from "../Bytes.sol"; library ScaleCodec { // Decodes a SCALE encoded uint256 by converting bytes (bid endian) to little endian format function decodeUint256(bytes memory data) internal pure returns (uint256) { uint256 number; for (uint256 i = data.length; i > 0; i--) { number = number + uint256(uint8(data[i - 1])) * (2 ** (8 * (i - 1))); } return number; } // Decodes a SCALE encoded compact unsigned integer function decodeUintCompact(ByteSlice memory data) internal pure returns (uint256 v) { uint8 b = Bytes.readByte(data); // read the first byte uint8 mode = b % 4; // bitwise operation uint256 value; if (mode == 0) { // [0, 63] value = b >> 2; // right shift to remove mode bits } else if (mode == 1) { // [64, 16383] uint8 bb = Bytes.readByte(data); // read the second byte uint64 r = bb; // convert to uint64 r <<= 6; // multiply by * 2^6 r += b >> 2; // right shift to remove mode bits value = r; } else if (mode == 2) { // [16384, 1073741823] uint8 b2 = Bytes.readByte(data); // read the next 3 bytes uint8 b3 = Bytes.readByte(data); uint8 b4 = Bytes.readByte(data); uint32 x1 = uint32(b) | (uint32(b2) << 8); // convert to little endian uint32 x2 = x1 | (uint32(b3) << 16); uint32 x3 = x2 | (uint32(b4) << 24); x3 >>= 2; // remove the last 2 mode bits value = uint256(x3); } else if (mode == 3) { // [1073741824, 4503599627370496] uint8 l = (b >> 2) + 4; // remove mode bits require(l <= 8, "unexpected prefix decoding Compact<Uint>"); return decodeUint256(Bytes.read(data, l)); } else { revert("Code should be unreachable"); } return value; } // Decodes a SCALE encoded compact unsigned integer function decodeUintCompact(bytes memory data) internal pure returns (uint256 v, uint8 m) { uint8 b = readByteAtIndex(data, 0); // read the first byte uint8 mode = b & 3; // bitwise operation uint256 value; if (mode == 0) { // [0, 63] value = b >> 2; // right shift to remove mode bits } else if (mode == 1) { // [64, 16383] uint8 bb = readByteAtIndex(data, 1); // read the second byte uint64 r = bb; // convert to uint64 r <<= 6; // multiply by * 2^6 r += b >> 2; // right shift to remove mode bits value = r; } else if (mode == 2) { // [16384, 1073741823] uint8 b2 = readByteAtIndex(data, 1); // read the next 3 bytes uint8 b3 = readByteAtIndex(data, 2); uint8 b4 = readByteAtIndex(data, 3); uint32 x1 = uint32(b) | (uint32(b2) << 8); // convert to little endian uint32 x2 = x1 | (uint32(b3) << 16); uint32 x3 = x2 | (uint32(b4) << 24); x3 >>= 2; // remove the last 2 mode bits value = uint256(x3); } else if (mode == 3) { // [1073741824, 4503599627370496] uint8 l = b >> 2; // remove mode bits require(l > 32, "Not supported: number cannot be greater than 32 bytes"); } else { revert("Code should be unreachable"); } return (value, mode); } // The biggest compact supported uint is 2 ** 536 - 1. // But the biggest value supported by this method is 2 ** 256 - 1(max of uint256) function encodeUintCompact(uint256 v) internal pure returns (bytes memory) { if (v < 64) { return abi.encodePacked(uint8(v << 2)); } else if (v < 2 ** 14) { return abi.encodePacked(reverse16(uint16(((v << 2) + 1)))); } else if (v < 2 ** 30) { return abi.encodePacked(reverse32(uint32(((v << 2) + 2)))); } else { bytes memory valueBytes = Bytes.removeEndingZero(abi.encodePacked(reverse256(v))); uint256 length = valueBytes.length; uint8 prefix = uint8(((length - 4) << 2) + 3); return abi.encodePacked(prefix, valueBytes); } } // Read a byte at a specific index and return it as type uint8 function readByteAtIndex(bytes memory data, uint8 index) internal pure returns (uint8) { return uint8(data[index]); } // Sources: // * https://ethereum.stackexchange.com/questions/15350/how-to-convert-an-bytes-to-address-in-solidity/50528 // * https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel function reverse256(uint256 input) internal pure returns (uint256 v) { v = input; // swap bytes v = ((v & 0xFF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00) >> 8) | ((v & 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) << 8); // swap 2-byte long pairs v = ((v & 0xFFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000) >> 16) | ((v & 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) << 16); // swap 4-byte long pairs v = ((v & 0xFFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000) >> 32) | ((v & 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) << 32); // swap 8-byte long pairs v = ((v & 0xFFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF0000000000000000) >> 64) | ((v & 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) << 64); // swap 16-byte long pairs v = (v >> 128) | (v << 128); } function reverse128(uint128 input) internal pure returns (uint128 v) { v = input; // swap bytes v = ((v & 0xFF00FF00FF00FF00FF00FF00FF00FF00) >> 8) | ((v & 0x00FF00FF00FF00FF00FF00FF00FF00FF) << 8); // swap 2-byte long pairs v = ((v & 0xFFFF0000FFFF0000FFFF0000FFFF0000) >> 16) | ((v & 0x0000FFFF0000FFFF0000FFFF0000FFFF) << 16); // swap 4-byte long pairs v = ((v & 0xFFFFFFFF00000000FFFFFFFF00000000) >> 32) | ((v & 0x00000000FFFFFFFF00000000FFFFFFFF) << 32); // swap 8-byte long pairs v = (v >> 64) | (v << 64); } function reverse64(uint64 input) internal pure returns (uint64 v) { v = input; // swap bytes v = ((v & 0xFF00FF00FF00FF00) >> 8) | ((v & 0x00FF00FF00FF00FF) << 8); // swap 2-byte long pairs v = ((v & 0xFFFF0000FFFF0000) >> 16) | ((v & 0x0000FFFF0000FFFF) << 16); // swap 4-byte long pairs v = (v >> 32) | (v << 32); } function reverse32(uint32 input) internal pure returns (uint32 v) { v = input; // swap bytes v = ((v & 0xFF00FF00) >> 8) | ((v & 0x00FF00FF) << 8); // swap 2-byte long pairs v = (v >> 16) | (v << 16); } function reverse16(uint16 input) internal pure returns (uint16 v) { v = input; // swap bytes v = (v >> 8) | (v << 8); } function encode256(uint256 input) internal pure returns (bytes32) { return bytes32(reverse256(input)); } function encode128(uint128 input) internal pure returns (bytes16) { return bytes16(reverse128(input)); } function encode64(uint64 input) internal pure returns (bytes8) { return bytes8(reverse64(input)); } function encode32(uint32 input) internal pure returns (bytes4) { return bytes4(reverse32(input)); } function encode16(uint16 input) internal pure returns (bytes2) { return bytes2(reverse16(input)); } function encodeBytes(bytes memory input) internal pure returns (bytes memory) { return abi.encodePacked(encodeUintCompact(input.length), input); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/Math.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } }
// SPDX-License-Identifier: Apache-2.0 /* * @author Hamdi Allam [email protected] * Please reach out with any questions or concerns */ pragma solidity >=0.5.10 <0.9.0; 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)) } } } }
{ "remappings": [ "@polytope-labs/ismp-solidity/=node_modules/@polytope-labs/ismp-solidity/interfaces/", "openzeppelin/=node_modules/openzeppelin-solidity/contracts/", "@polytope-labs/solidity-merkle-trees/=node_modules/@polytope-labs/solidity-merkle-trees/src/", "@polytope-labs/erc6160/=node_modules/@polytope-labs/erc6160/src/", "@uniswap/v2-periphery/=node_modules/@uniswap/v2-periphery/", "stringutils/=lib/solidity-stringutils/src/", "ds-test/=lib/forge-std/lib/ds-test/src/", "forge-std/=lib/forge-std/src/", "solidity-stringutils/=lib/solidity-stringutils/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "libraries": { "node_modules/@polytope-labs/solidity-merkle-trees/src/MerklePatricia.sol": { "MerklePatricia": "0xd8e040255903d5534b41cc7b0b256f76dcdb343c" }, "node_modules/@polytope-labs/solidity-merkle-trees/src/trie/ethereum/EthereumTrieDB.sol": { "EthereumTrieDB": "0x669bc248b74ad0657fdfc59b557f21d3c415be31" }, "src/consensus/Header.sol": { "HeaderImpl": "0xe27eecad5fbc5b4c2a77cbbd5700df11cdb89ed8" } } }
[{"inputs":[],"name":"ChallengePeriodNotElapsed","type":"error"},{"inputs":[],"name":"ConsensusClientExpired","type":"error"},{"inputs":[],"name":"DuplicateMessage","type":"error"},{"inputs":[],"name":"HostFrozen","type":"error"},{"inputs":[],"name":"InvalidMessageDestination","type":"error"},{"inputs":[],"name":"InvalidProof","type":"error"},{"inputs":[],"name":"MessageNotTimedOut","type":"error"},{"inputs":[],"name":"MessageTimedOut","type":"error"},{"inputs":[],"name":"StateCommitmentNotFound","type":"error"},{"inputs":[],"name":"UnknownMessage","type":"error"},{"inputs":[{"internalType":"contract IIsmpHost","name":"host","type":"address"},{"internalType":"bytes","name":"proof","type":"bytes"}],"name":"handleConsensus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IIsmpHost","name":"host","type":"address"},{"components":[{"components":[{"internalType":"bytes","name":"source","type":"bytes"},{"internalType":"bytes","name":"dest","type":"bytes"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"},{"internalType":"bytes[]","name":"keys","type":"bytes[]"},{"internalType":"uint64","name":"height","type":"uint64"}],"internalType":"struct GetRequest[]","name":"timeouts","type":"tuple[]"}],"internalType":"struct GetTimeoutMessage","name":"message","type":"tuple"}],"name":"handleGetRequestTimeouts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IIsmpHost","name":"host","type":"address"},{"components":[{"internalType":"bytes[]","name":"proof","type":"bytes[]"},{"components":[{"internalType":"uint256","name":"stateMachineId","type":"uint256"},{"internalType":"uint256","name":"height","type":"uint256"}],"internalType":"struct StateMachineHeight","name":"height","type":"tuple"},{"components":[{"internalType":"bytes","name":"source","type":"bytes"},{"internalType":"bytes","name":"dest","type":"bytes"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"},{"internalType":"bytes[]","name":"keys","type":"bytes[]"},{"internalType":"uint64","name":"height","type":"uint64"}],"internalType":"struct GetRequest[]","name":"requests","type":"tuple[]"}],"internalType":"struct GetResponseMessage","name":"message","type":"tuple"}],"name":"handleGetResponses","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IIsmpHost","name":"host","type":"address"},{"components":[{"components":[{"internalType":"bytes","name":"source","type":"bytes"},{"internalType":"bytes","name":"dest","type":"bytes"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"bytes","name":"from","type":"bytes"},{"internalType":"bytes","name":"to","type":"bytes"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"},{"internalType":"bytes","name":"body","type":"bytes"}],"internalType":"struct PostRequest[]","name":"timeouts","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"stateMachineId","type":"uint256"},{"internalType":"uint256","name":"height","type":"uint256"}],"internalType":"struct StateMachineHeight","name":"height","type":"tuple"},{"internalType":"bytes[]","name":"proof","type":"bytes[]"}],"internalType":"struct PostRequestTimeoutMessage","name":"message","type":"tuple"}],"name":"handlePostRequestTimeouts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IIsmpHost","name":"host","type":"address"},{"components":[{"components":[{"components":[{"internalType":"uint256","name":"stateMachineId","type":"uint256"},{"internalType":"uint256","name":"height","type":"uint256"}],"internalType":"struct StateMachineHeight","name":"height","type":"tuple"},{"internalType":"bytes32[]","name":"multiproof","type":"bytes32[]"},{"internalType":"uint256","name":"leafCount","type":"uint256"}],"internalType":"struct Proof","name":"proof","type":"tuple"},{"components":[{"components":[{"internalType":"bytes","name":"source","type":"bytes"},{"internalType":"bytes","name":"dest","type":"bytes"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"bytes","name":"from","type":"bytes"},{"internalType":"bytes","name":"to","type":"bytes"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"},{"internalType":"bytes","name":"body","type":"bytes"}],"internalType":"struct PostRequest","name":"request","type":"tuple"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"kIndex","type":"uint256"}],"internalType":"struct PostRequestLeaf[]","name":"requests","type":"tuple[]"}],"internalType":"struct PostRequestMessage","name":"request","type":"tuple"}],"name":"handlePostRequests","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IIsmpHost","name":"host","type":"address"},{"components":[{"components":[{"components":[{"internalType":"bytes","name":"source","type":"bytes"},{"internalType":"bytes","name":"dest","type":"bytes"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"bytes","name":"from","type":"bytes"},{"internalType":"bytes","name":"to","type":"bytes"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"},{"internalType":"bytes","name":"body","type":"bytes"}],"internalType":"struct PostRequest","name":"request","type":"tuple"},{"internalType":"bytes","name":"response","type":"bytes"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"}],"internalType":"struct PostResponse[]","name":"timeouts","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"stateMachineId","type":"uint256"},{"internalType":"uint256","name":"height","type":"uint256"}],"internalType":"struct StateMachineHeight","name":"height","type":"tuple"},{"internalType":"bytes[]","name":"proof","type":"bytes[]"}],"internalType":"struct PostResponseTimeoutMessage","name":"message","type":"tuple"}],"name":"handlePostResponseTimeouts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IIsmpHost","name":"host","type":"address"},{"components":[{"components":[{"components":[{"internalType":"uint256","name":"stateMachineId","type":"uint256"},{"internalType":"uint256","name":"height","type":"uint256"}],"internalType":"struct StateMachineHeight","name":"height","type":"tuple"},{"internalType":"bytes32[]","name":"multiproof","type":"bytes32[]"},{"internalType":"uint256","name":"leafCount","type":"uint256"}],"internalType":"struct Proof","name":"proof","type":"tuple"},{"components":[{"components":[{"components":[{"internalType":"bytes","name":"source","type":"bytes"},{"internalType":"bytes","name":"dest","type":"bytes"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"bytes","name":"from","type":"bytes"},{"internalType":"bytes","name":"to","type":"bytes"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"},{"internalType":"bytes","name":"body","type":"bytes"}],"internalType":"struct PostRequest","name":"request","type":"tuple"},{"internalType":"bytes","name":"response","type":"bytes"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"}],"internalType":"struct PostResponse","name":"response","type":"tuple"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"kIndex","type":"uint256"}],"internalType":"struct PostResponseLeaf[]","name":"responses","type":"tuple[]"}],"internalType":"struct PostResponseMessage","name":"response","type":"tuple"}],"name":"handlePostResponses","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b50614dcc806100206000396000f3fe608060405234801561001057600080fd5b50600436106100885760003560e01c80639d38eb351161005b5780639d38eb35146100ef578063bb1689be14610102578063e407f86b14610115578063ee241c0d1461012857600080fd5b806301ffc9a71461008d578063089b174c146100b45780632e8f454b146100c957806372becccd146100dc575b600080fd5b6100a061009b366004613b02565b61013b565b604051901515815260200160405180910390f35b6100c76100c2366004613b5c565b610172565b005b6100c76100d7366004613b5c565b61071e565b6100c76100ea366004613bbd565b610cc8565b6100c76100fd366004613bbd565b611346565b6100c7610110366004613c02565b61193b565b6100c7610123366004613b5c565b611db4565b6100c7610136366004613c86565b612356565b60006001600160e01b031982166378a7182760e01b148061016c57506301ffc9a760e01b6001600160e01b03198316145b92915050565b816000816001600160a01b031663054f7d9c6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101d79190613cdc565b905060018160038111156101ed576101ed613cfd565b148061020a5750600381600381111561020857610208613cfd565b145b1561022857604051631c6d5f7760e31b815260040160405180910390fd5b60408051631a880a9360e01b8152602085013560048201529084013560248201526000906001600160a01b03861690631a880a93906044016020604051808303816000875af115801561027f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102a39190613d13565b6102ad9042613d42565b90506000856001600160a01b031663f3f480d96040518163ffffffff1660e01b8152600401602060405180830381865afa1580156102ef573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103139190613d13565b9050801580159061032357508181115b156103415760405163048c969960e01b815260040160405180910390fd5b6040805163a70a8c4760e01b8152602087013560048201529086013560248201526000906001600160a01b0388169063a70a8c47906044016060604051808303816000875af1158015610398573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103bc9190613e41565b60408101519091506103e1576040516353ae552b60e11b815260040160405180910390fd5b60006103ed8780613e5d565b9050905060005b818110156107135760006104088980613e5d565b8381811061041857610418613ea6565b905060200281019061042a9190613ebc565b6104339061406f565b8451909150610441826125b9565b6001600160401b03161115610469576040516348e8dd2f60e11b815260040160405180910390fd5b6000610474826125eb565b604051630da2fd1960e21b8152600481018290529091506000906001600160a01b038d169063368bf464906024016040805180830381865afa1580156104be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104e2919061407b565b60208101519091506001600160a01b03166105105760405163f058bfd960e01b815260040160405180910390fd5b604080516001808252818301909252600091816020015b60608152602001906001900390816105275790505090506040518060400160405280600f81526020016e52657175657374526563656970747360881b8152508360405160200161057991815260200190565b60408051601f198184030181529082905261059792916020016140d7565b6040516020818303038152906040528186815181106105b8576105b8613ea6565b6020026020010181905250600073d8e040255903d5534b41cc7b0b256f76dcdb343c631475ff4589604001518f80606001906105f49190613e5d565b866040518563ffffffff1660e01b815260040161061494939291906141b0565b600060405180830381865af4158015610631573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261065991908101906142cf565b60008151811061066b5761066b613ea6565b6020026020010151905080602001515160001461069b576040516309bde33960e01b815260040160405180910390fd5b6040516325a377d560e11b81526001600160a01b038f1690634b46efaa906106cb9088908790899060040161447b565b600060405180830381600087803b1580156106e557600080fd5b505af11580156106f9573d6000803e3d6000fd5b5050505050505050508061070c906144be565b90506103f4565b505050505050505050565b816000816001600160a01b031663054f7d9c6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561075f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107839190613cdc565b9050600181600381111561079957610799613cfd565b14806107b6575060038160038111156107b4576107b4613cfd565b145b156107d457604051631c6d5f7760e31b815260040160405180910390fd5b60408051631a880a9360e01b81526020850135600482015290840135602482015242906000906001600160a01b03871690631a880a93906044016020604051808303816000875af115801561082d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108519190613d13565b61085b9083613d42565b90506000866001600160a01b031663f3f480d96040518163ffffffff1660e01b8152600401602060405180830381865afa15801561089d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108c19190613d13565b905080158015906108d157508181115b156108ef5760405163048c969960e01b815260040160405180910390fd5b6040805163a70a8c4760e01b8152602088013560048201529087013560248201526000906001600160a01b0389169063a70a8c47906044016060604051808303816000875af1158015610946573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096a9190613e41565b6040015190508061098e576040516353ae552b60e11b815260040160405180910390fd5b600061099d6060890189613e5d565b9150600090506109ad8980613e5d565b6109b69161454a565b905060005b82811015610cbb5760006109d260608c018c613e5d565b838181106109e2576109e2613ea6565b90506020028101906109f49190613ebc565b6109fd90614582565b9050610a0881612604565b6001600160401b03168810610a3057604051631676f4b360e01b815260040160405180910390fd5b6000610a3b82612631565b604051630da2fd1960e21b8152600481018290529091506000906001600160a01b038f169063368bf464906024016040805180830381865afa158015610a85573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa9919061407b565b60208101519091506001600160a01b0316610ad75760405163f058bfd960e01b815260040160405180910390fd5b60006001600160a01b03168e6001600160a01b0316638856337e846040518263ffffffff1660e01b8152600401610b1091815260200190565b6040805180830381865afa158015610b2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b50919061407b565b602001516001600160a01b031614610b7b5760405163156a571760e11b815260040160405180910390fd5b600073d8e040255903d5534b41cc7b0b256f76dcdb343c6355028f6f89888760a0015187604051602001610bb191815260200190565b6040516020818303038152906040526040518563ffffffff1660e01b8152600401610bdf9493929190614657565b600060405180830381865af4158015610bfc573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610c2491908101906142cf565b9050600060405180604001604052808681526020018381525090508f6001600160a01b031663ff279b9882610c563390565b6040518363ffffffff1660e01b8152600401610c7392919061472d565b600060405180830381600087803b158015610c8d57600080fd5b505af1158015610ca1573d6000803e3d6000fd5b50505050505050505080610cb4906144be565b90506109bb565b5050505050505050505050565b816000816001600160a01b031663054f7d9c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d2d9190613cdc565b90506001816003811115610d4357610d43613cfd565b1480610d6057506003816003811115610d5e57610d5e613cfd565b145b15610d7e57604051631c6d5f7760e31b815260040160405180910390fd5b4260006001600160a01b038616631a880a93610d9a87806147eb565b60405160e083901b6001600160e01b03191681528135600482015260209091013560248201526044016020604051808303816000875af1158015610de2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e069190613d13565b610e109083613d42565b90506000866001600160a01b031663f3f480d96040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e52573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e769190613d13565b90508015801590610e8657508181115b15610ea45760405163048c969960e01b815260040160405180910390fd5b6000610eb36020880188613e5d565b905090506000816001600160401b03811115610ed157610ed1613d55565b604051908082528060200260200182016040528015610f1c57816020015b6040805160608101825260008082526020808301829052928201528252600019909201910181610eef5790505b50905060005b82811015611156576000610f3960208b018b613e5d565b83818110610f4957610f49613ea6565b9050602002810190610f5b9190614801565b610f6490614896565b9050610f738160000151612732565b6001600160401b03168710610f9b57604051631676f4b360e01b815260040160405180910390fd5b805151600090610faa906125eb565b604051630da2fd1960e21b8152600481018290529091506000906001600160a01b038e169063368bf464906024016040805180830381865afa158015610ff4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611018919061407b565b60208101519091506001600160a01b0316611046576040516309bde33960e01b815260040160405180910390fd5b60006001600160a01b03168d6001600160a01b0316638856337e61106d866000015161275f565b6040518263ffffffff1660e01b815260040161108b91815260200190565b6040805180830381865afa1580156110a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110cb919061407b565b602001516001600160a01b0316146110f65760405163156a571760e11b815260040160405180910390fd5b60405180606001604052808460400151815260200184602001518152602001611122856000015161275f565b81525085858151811061113757611137613ea6565b60200260200101819052505050508061114f906144be565b9050610f22565b5060006001600160a01b038a1663a70a8c476111728b806147eb565b60405160e083901b6001600160e01b03191681528135600482015260209091013560248201526044016060604051808303816000875af11580156111ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111de9190613e41565b60200151905080611202576040516353ae552b60e11b815260040160405180910390fd5b611266816112108b806147eb565b61121e906040810190613e5d565b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525087925061125d91508e9050806147eb565b606001356127c1565b611283576040516309bde33960e01b815260040160405180910390fd5b60005b83811015610cbb57600061129d60208c018c613e5d565b838181106112ad576112ad613ea6565b90506020028101906112bf9190614801565b6112c890614896565b90508b6001600160a01b031663ab013de182600001516112e53390565b6040518363ffffffff1660e01b8152600401611302929190614940565b600060405180830381600087803b15801561131c57600080fd5b505af1158015611330573d6000803e3d6000fd5b50505050508061133f906144be565b9050611286565b816000816001600160a01b031663054f7d9c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611387573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113ab9190613cdc565b905060018160038111156113c1576113c1613cfd565b14806113de575060038160038111156113dc576113dc613cfd565b145b156113fc57604051631c6d5f7760e31b815260040160405180910390fd5b4260006001600160a01b038616631a880a9361141887806147eb565b60405160e083901b6001600160e01b03191681528135600482015260209091013560248201526044016020604051808303816000875af1158015611460573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114849190613d13565b61148e9083613d42565b90506000866001600160a01b031663f3f480d96040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114f49190613d13565b9050801580159061150457508181115b156115225760405163048c969960e01b815260040160405180910390fd5b60006115316020880188613e5d565b905090506000816001600160401b0381111561154f5761154f613d55565b60405190808252806020026020018201604052801561159a57816020015b604080516060810182526000808252602080830182905292820152825260001990920191018161156d5790505b50905060005b828110156117a15760006115b760208b018b613e5d565b838181106115c7576115c7613ea6565b90506020028101906115d99190614801565b6115e29061496a565b90506116598b6001600160a01b031663f437bc596040518163ffffffff1660e01b8152600401600060405180830381865afa158015611625573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261164d91908101906149a6565b825160200151906127d9565b611676576040516390d4c20960e01b815260040160405180910390fd5b8051611681906125b9565b6001600160401b031687106116a957604051631676f4b360e01b815260040160405180910390fd5b60006116b882600001516125eb565b604051630cb33d1f60e11b8152600481018290529091506000906001600160a01b038e16906319667a3e90602401602060405180830381865afa158015611703573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061172791906149da565b6001600160a01b03161461174e5760405163156a571760e11b815260040160405180910390fd5b604051806060016040528083604001518152602001836020015181526020018281525084848151811061178357611783613ea6565b602002602001018190525050508061179a906144be565b90506115a0565b5060006001600160a01b038a1663a70a8c476117bd8b806147eb565b60405160e083901b6001600160e01b03191681528135600482015260209091013560248201526044016060604051808303816000875af1158015611805573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118299190613e41565b6020015190508061184d576040516353ae552b60e11b815260040160405180910390fd5b61185b816112108b806147eb565b611878576040516309bde33960e01b815260040160405180910390fd5b60005b83811015610cbb57600061189260208c018c613e5d565b838181106118a2576118a2613ea6565b90506020028101906118b49190614801565b6118bd9061496a565b90508b6001600160a01b031663b85e6fbb82600001516118da3390565b6040518363ffffffff1660e01b81526004016118f79291906149f7565b600060405180830381600087803b15801561191157600080fd5b505af1158015611925573d6000803e3d6000fd5b505050505080611934906144be565b905061187b565b826000816001600160a01b031663054f7d9c6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561197c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119a09190613cdc565b905060018160038111156119b6576119b6613cfd565b14806119d3575060038160038111156119d1576119d1613cfd565b145b156119f157604051631c6d5f7760e31b815260040160405180910390fd5b6000856001600160a01b0316639a8425bc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a559190613d13565b611a5f9042613d42565b9050856001600160a01b031663d40784c76040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ac39190613d13565b8110611ae25760405163040dc5c360e41b815260040160405180910390fd5b600080876001600160a01b0316632476132b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b23573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b4791906149da565b6001600160a01b0316637d755598896001600160a01b031663bbad99d46040518163ffffffff1660e01b8152600401600060405180830381865afa158015611b93573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611bbb91908101906149a6565b89896040518463ffffffff1660e01b8152600401611bdb93929190614a0a565b6000604051808303816000875af1158015611bfa573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611c229190810190614a3a565b604051630b4974cf60e41b815291935091506001600160a01b0389169063b4974cf090611c53908590600401614abc565b600060405180830381600087803b158015611c6d57600080fd5b505af1158015611c81573d6000803e3d6000fd5b50508251604051634e04afc360e11b8152600093506001600160a01b038c169250639c095f8691611cb89160040190815260200190565b602060405180830381865afa158015611cd5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cf99190613d13565b90508015801590611d0d5750808260200151115b156107135760408051808201825283518152602080850151818301908152858401518451632acf7f4f60e11b81528451600482015291516024830152805160448301529182015160648201529201516084830152906001600160a01b038b169063559efe9e9060a401600060405180830381600087803b158015611d9057600080fd5b505af1158015611da4573d6000803e3d6000fd5b5050505050505050505050505050565b816000816001600160a01b031663054f7d9c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611df5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e199190613cdc565b90506001816003811115611e2f57611e2f613cfd565b1480611e4c57506003816003811115611e4a57611e4a613cfd565b145b15611e6a57604051631c6d5f7760e31b815260040160405180910390fd5b60408051631a880a9360e01b8152602085013560048201529084013560248201526000906001600160a01b03861690631a880a93906044016020604051808303816000875af1158015611ec1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ee59190613d13565b611eef9042613d42565b90506000856001600160a01b031663f3f480d96040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f559190613d13565b90508015801590611f6557508181115b15611f835760405163048c969960e01b815260040160405180910390fd5b6040805163a70a8c4760e01b8152602087013560048201529086013560248201526000906001600160a01b0388169063a70a8c47906044016060604051808303816000875af1158015611fda573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ffe9190613e41565b6040810151909150612023576040516353ae552b60e11b815260040160405180910390fd5b600061202f8780613e5d565b9050905060005b8181101561071357600061204a8980613e5d565b8381811061205a5761205a613ea6565b905060200281019061206c9190614801565b61207590614acf565b845190915061208382612732565b6001600160401b031611156120ab576040516348e8dd2f60e11b815260040160405180910390fd5b60006120b68261275f565b604051632211f1dd60e01b8152600481018290529091506000906001600160a01b038d1690632211f1dd906024016040805180830381865afa158015612100573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612124919061407b565b60208101519091506001600160a01b03166121525760405163f058bfd960e01b815260040160405180910390fd5b604080516001808252818301909252600091816020015b60608152602001906001900390816121695790505090506040518060400160405280601081526020016f526573706f6e7365526563656970747360801b815250836040516020016121bc91815260200190565b60408051601f19818403018152908290526121da92916020016140d7565b6040516020818303038152906040528186815181106121fb576121fb613ea6565b6020026020010181905250600073d8e040255903d5534b41cc7b0b256f76dcdb343c631475ff4589604001518f80606001906122379190613e5d565b866040518563ffffffff1660e01b815260040161225794939291906141b0565b600060405180830381865af4158015612274573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261229c91908101906142cf565b6000815181106122ae576122ae613ea6565b602002602001015190508060200151516000146122de576040516309bde33960e01b815260040160405180910390fd5b604051630446fc4760e01b81526001600160a01b038f1690630446fc479061230e90889087908990600401614adb565b600060405180830381600087803b15801561232857600080fd5b505af115801561233c573d6000803e3d6000fd5b5050505050505050508061234f906144be565b9050612036565b816000816001600160a01b031663054f7d9c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612397573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123bb9190613cdc565b905060018160038111156123d1576123d1613cfd565b14806123ee575060038160038111156123ec576123ec613cfd565b145b1561240c57604051631c6d5f7760e31b815260040160405180910390fd5b60006124188480613e5d565b915042905060005b828110156125b05760006124348780613e5d565b8381811061244457612444613ea6565b90506020028101906124569190613ebc565b61245f90614582565b9050600061246c82612631565b604051630da2fd1960e21b8152600481018290529091506000906001600160a01b038b169063368bf464906024016040805180830381865afa1580156124b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124da919061407b565b60208101519091506001600160a01b0316612508576040516309bde33960e01b815260040160405180910390fd5b8461251284612604565b6001600160401b0316111561253a576040516348e8dd2f60e11b815260040160405180910390fd5b60405163017d055b60e11b81526001600160a01b038b16906302fa0ab69061256a90869085908790600401614aee565b600060405180830381600087803b15801561258457600080fd5b505af1158015612598573d6000803e3d6000fd5b50505050505050806125a9906144be565b9050612420565b50505050505050565b60008160a001516001600160401b03166000036125de57506001600160401b03919050565b5060a0015190565b919050565b60006125f682612809565b805190602001209050919050565b600081608001516001600160401b031660000361262957506001600160401b03919050565b506080015190565b6040805160208101909152600080825260a083015151909190825b818110156126a857828560a00151828151811061266b5761266b613ea6565b60200260200101516040516020016126849291906140d7565b604051602081830303815290604052925080806126a0906144be565b91505061264c565b508360000151846020015185604001518660c00151876080015188606001516040516020016126ef919060609190911b6bffffffffffffffffffffffff1916815260140190565b60408051601f19818403018152908290526127139695949392918990602001614b01565b6040516020818303038152906040528051906020012092505050919050565b600081604001516001600160401b031660000361275757506001600160401b03919050565b506040015190565b600061276e8260000151612809565b60208084015160408086015190516127869301614b8c565b60408051601f19818403018152908290526127a492916020016140d7565b604051602081830303815290604052805190602001209050919050565b60006127ce84848461285a565b909414949350505050565b600081518351146127ec5750600061016c565b825160208381018281209186019283209091145b95945050505050565b60608160000151826020015183604001518460a00151856060015186608001518760c001516040516020016128449796959493929190614bbe565b6040516020818303038152906040529050919050565b600081600114801561286d575082516001145b801561289757508260008151811061288757612887613ea6565b6020026020010151602001516000145b156128c257826000815181106128af576128af613ea6565b6020026020010151604001519050612b21565b60006128cd83612b28565b90506000815190506000604051806040016040528060008152602001836001600160401b0381111561290157612901613d55565b60405190808252806020026020018201604052801561292a578160200160208202803683370190505b509052604080518082019091526000808252602082018a905291925090805b84811015612a7057600086828151811061296557612965613ea6565b6020026020010151905080600261297c9190614d39565b6129869084614d45565b6040805160008082526020820190925291945090816129cd565b60408051606081018252600080825260208083018290529282015282526000199092019101816129a05790505b508b51909150156129e7576129e28b85612bcb565b9b5090505b8051600003612a1b57845160208601515103612a04575050612a70565b612a1686612a1187612dca565b612e01565b612a66565b80516001148015612a2a575081155b15612a5757612a168682600081518110612a4657612a46613ea6565b602002602001015160400151612e01565b612a6686612a11838886612e31565b5050600101612949565b5082516000190183525b825115612afa576000612a8c8461300e565b90506000612a998561300e565b855160010186526040805160208101859052908101829052909150606001604051602081830303815290604052805190602001208560200151866000015181518110612ae757612ae7613ea6565b6020026020010181815250505050612a7a565b8260200151600081518110612b1157612b11613ea6565b6020026020010151955050505050505b9392505050565b6040805181815261082081018252606091906000908260208201610800803683370190505090506000845b83821015612baf578015612baf576000612b6c82613046565b905080848481518110612b8157612b81613ea6565b6020908102919091010152612b97816002614d39565b612ba19083613d42565b915082600101925050612b53565b6000612bbb8386613d42565b8451038452509195945050505050565b606080600080855190505b80821015612c1557858281518110612bf057612bf0613ea6565b602002602001015160200151851115612c155781612c0d816144be565b925050612bd6565b60008215612c235782612c26565b60005b90506000816001600160401b03811115612c4257612c42613d55565b604051908082528060200260200182016040528015612c8d57816020015b6040805160608101825260008082526020808301829052928201528252600019909201910181612c605790505b5090506000612c9c8385613d42565b6001600160401b03811115612cb357612cb3613d55565b604051908082528060200260200182016040528015612cfe57816020015b6040805160608101825260008082526020808301829052928201528252600019909201910181612cd15790505b5082519091506000905b80821015612d58578a8281518110612d2257612d22613ea6565b6020026020010151848381518110612d3c57612d3c613ea6565b602002602001018190525081612d51906144be565b9150612d08565b60005b86831015612db6578b8381518110612d7557612d75613ea6565b6020026020010151848281518110612d8f57612d8f613ea6565b602002602001018190525082612da4906144be565b9250612daf816144be565b9050612d5b565b5092975090955050505050505b9250929050565b6000808260200151836000015181518110612de757612de7613ea6565b602090810291909101015183516001019093525090919050565b808260200151836000015181518110612e1c57612e1c613ea6565b60209081029190910101525080516001019052565b6000606080612e3f866130da565b925090506000846001600160401b03811115612e5d57612e5d613d55565b604051908082528060200260200182016040528015612e9057816020015b6060815260200190600190039081612e7b5790505b50905060005b85811015612ff8576000612eaa8288613d42565b612eb5906002614d39565b905080855103612ec55750612ff8565b6000612ed086613258565b90506000612ede828861335a565b8051909150806001600160401b03811115612efb57612efb613d55565b604051908082528060200260200182016040528015612f4057816020015b6040805180820190915260008082526020820152815260200190600190039081612f195790505b50868681518110612f5357612f53613ea6565b602002602001018190525060005b81811015612fdd576040518060400160405280848381518110612f8657612f86613ea6565b60200260200101518152602001612f9c8e612dca565b815250878781518110612fb157612fb1613ea6565b60200260200101518281518110612fca57612fca613ea6565b6020908102919091010152600101612f61565b50612fe78361347c565b975084600101945050505050612e96565b50613003818361358f565b979650505050505050565b600080826020015183600001518151811061302b5761302b613ea6565b60209081029190910101518351600019019093525090919050565b600080608083901c1561305b57608092831c92015b604083901c1561306d57604092831c92015b602083901c1561307f57602092831c92015b601083901c1561309157601092831c92015b600883901c156130a357600892831c92015b600483901c156130b557600492831c92015b600283901c156130c757600292831c92015b600183901c1561016c5760010192915050565b606080600080845190506000816001600160401b038111156130fe576130fe613d55565b60405190808252806020026020018201604052801561314357816020015b604080518082019091526000808252602082015281526020019060019003908161311c5790505b5090506000826001600160401b0381111561316057613160613d55565b604051908082528060200260200182016040528015613189578160200160208202803683370190505b5090505b8284101561324c5760405180604001604052808886815181106131b2576131b2613ea6565b60200260200101516000015181526020018886815181106131d5576131d5613ea6565b6020026020010151604001518152508285815181106131f6576131f6613ea6565b602002602001018190525086848151811061321357613213613ea6565b60200260200101516000015181858151811061323157613231613ea6565b6020908102919091010152613245846144be565b935061318d565b90969095509350505050565b80516060906000816001600160401b0381111561327757613277613d55565b6040519080825280602002602001820160405280156132a0578160200160208202803683370190505b50905060005b828110156133525760008582815181106132c2576132c2613ea6565b6020026020010151905080600003613302576132df816001614d45565b8383815181106132f1576132f1613ea6565b602002602001018181525050613349565b61330d600282614d6e565b60000361331f576132df816001614d45565b61332a600182613d42565b83838151811061333c5761333c613ea6565b6020026020010181815250505b506001016132a6565b509392505050565b81518151606091906000826001600160401b0381111561337c5761337c613d55565b6040519080825280602002602001820160405280156133a5578160200160208202803683370190505b5090506000805b8481101561345e576000805b8581101561340a578881815181106133d2576133d2613ea6565b60200260200101518a84815181106133ec576133ec613ea6565b602002602001015103613402576001915061340a565b6001016133b8565b50806134555788828151811061342257613422613ea6565b602002602001015184848151811061343c5761343c613ea6565b602090810291909101015282613451816144be565b9350505b506001016133ac565b50600061346b8286613d42565b835103835250909695505050505050565b80516060906000816001600160401b0381111561349b5761349b613d55565b6040519080825280602002602001820160405280156134c4578160200160208202803683370190505b5090506000805b8381101561357357600060028783815181106134e9576134e9613ea6565b60200260200101516134fb9190614d82565b905060008311801561352f57508084613515600186613d42565b8151811061352557613525613ea6565b6020026020010151145b1561353a5750613561565b8084848151811061354d5761354d613ea6565b602002602001018181525050826001019250505b8061356b816144be565b9150506134cb565b5060006135808285613d42565b83510383525090949350505050565b604080516000808252602082019092528190816135ce565b60408051808201909152600080825260208201528152602001906001900390816135a75790505b5090506135f583856000815181106135e8576135e8613ea6565b60200260200101516138c2565b8460008151811061360857613608613ea6565b6020908102919091010152835160005b8181101561388a57604080516000808252602082019092528161365d565b60408051808201909152600080825260208201528152602001906001900390816136365790505b509050835160000361368a5786828151811061367b5761367b613ea6565b602002602001015190506136b0565b6136ad87838151811061369f5761369f613ea6565b6020026020010151856138c2565b90505b6136bc81516002613ace565b6001600160401b038111156136d3576136d3613d55565b60405190808252806020026020018201604052801561371857816020015b60408051808201909152600080825260208201528152602001906001900390816136f15790505b508151909450600090815b818110156138735781613737826001614d45565b106137ab57600084828151811061375057613750613ea6565b6020026020010151905061378285838151811061376f5761376f613ea6565b6020026020010151600001516002613af6565b81528751819089908690811061379a5761379a613ea6565b602002602001018190525050613861565b60408051808201909152600080825260208201526137d485838151811061376f5761376f613ea6565b81528451613833908690849081106137ee576137ee613ea6565b602002602001015160200151868460016138089190614d45565b8151811061381857613818613ea6565b60200260200101516020015160009182526020526040902090565b60208201528751819089908690811061384e5761384e613ea6565b6020908102919091010152506001909201915b61386c600282614d45565b9050613723565b505050508080613882906144be565b915050613618565b50815160011461389957600080fd5b816000815181106138ac576138ac613ea6565b6020026020010151602001519250505092915050565b8151815160609160009182918291826138db8284614d45565b90506000816001600160401b038111156138f7576138f7613d55565b60405190808252806020026020018201604052801561393c57816020015b60408051808201909152600080825260208201528152602001906001900390816139155790505b5090505b838710801561394e57508286105b15613a235788868151811061396557613965613ea6565b6020026020010151600001518a888151811061398357613983613ea6565b60200260200101516000015110156139dc578987815181106139a7576139a7613ea6565b60200260200101518186815181106139c1576139c1613ea6565b60209081029190910101526001968701969490940193613940565b8886815181106139ee576139ee613ea6565b6020026020010151818681518110613a0857613a08613ea6565b60209081029190910101526001958601959490940193613940565b83871015613a7257898781518110613a3d57613a3d613ea6565b6020026020010151818681518110613a5757613a57613ea6565b60209081029190910101526001968701969490940193613a23565b82861015613ac157888681518110613a8c57613a8c613ea6565b6020026020010151818681518110613aa657613aa6613ea6565b60209081029190910101526001958601959490940193613a72565b9998505050505050505050565b600080613adb8385614d82565b9050613ae78385614d6e565b15612b21576001019392505050565b6000612b218284614d82565b600060208284031215613b1457600080fd5b81356001600160e01b031981168114612b2157600080fd5b6001600160a01b0381168114613b4157600080fd5b50565b600060808284031215613b5657600080fd5b50919050565b60008060408385031215613b6f57600080fd5b8235613b7a81613b2c565b915060208301356001600160401b03811115613b9557600080fd5b613ba185828601613b44565b9150509250929050565b600060408284031215613b5657600080fd5b60008060408385031215613bd057600080fd5b8235613bdb81613b2c565b915060208301356001600160401b03811115613bf657600080fd5b613ba185828601613bab565b600080600060408486031215613c1757600080fd5b8335613c2281613b2c565b925060208401356001600160401b0380821115613c3e57600080fd5b818601915086601f830112613c5257600080fd5b813581811115613c6157600080fd5b876020828501011115613c7357600080fd5b6020830194508093505050509250925092565b60008060408385031215613c9957600080fd5b8235613ca481613b2c565b915060208301356001600160401b03811115613cbf57600080fd5b830160208186031215613cd157600080fd5b809150509250929050565b600060208284031215613cee57600080fd5b815160048110612b2157600080fd5b634e487b7160e01b600052602160045260246000fd5b600060208284031215613d2557600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561016c5761016c613d2c565b634e487b7160e01b600052604160045260246000fd5b604051606081016001600160401b0381118282101715613d8d57613d8d613d55565b60405290565b60405160e081016001600160401b0381118282101715613d8d57613d8d613d55565b604080519081016001600160401b0381118282101715613d8d57613d8d613d55565b604051601f8201601f191681016001600160401b0381118282101715613dff57613dff613d55565b604052919050565b600060608284031215613e1957600080fd5b613e21613d6b565b905081518152602082015160208201526040820151604082015292915050565b600060608284031215613e5357600080fd5b612b218383613e07565b6000808335601e19843603018112613e7457600080fd5b8301803591506001600160401b03821115613e8e57600080fd5b6020019150600581901b3603821315612dc357600080fd5b634e487b7160e01b600052603260045260246000fd5b6000823560de19833603018112613ed257600080fd5b9190910192915050565b60006001600160401b03821115613ef557613ef5613d55565b50601f01601f191660200190565b600082601f830112613f1457600080fd5b8135613f27613f2282613edc565b613dd7565b818152846020838601011115613f3c57600080fd5b816020850160208301376000918101602001919091529392505050565b80356001600160401b03811681146125e657600080fd5b600060e08284031215613f8257600080fd5b613f8a613d93565b905081356001600160401b0380821115613fa357600080fd5b613faf85838601613f03565b83526020840135915080821115613fc557600080fd5b613fd185838601613f03565b6020840152613fe260408501613f59565b60408401526060840135915080821115613ffb57600080fd5b61400785838601613f03565b6060840152608084013591508082111561402057600080fd5b61402c85838601613f03565b608084015261403d60a08501613f59565b60a084015260c084013591508082111561405657600080fd5b5061406384828501613f03565b60c08301525092915050565b600061016c3683613f70565b60006040828403121561408d57600080fd5b614095613db5565b8251815260208301516140a781613b2c565b60208201529392505050565b60005b838110156140ce5781810151838201526020016140b6565b50506000910152565b600083516140e98184602088016140b3565b8351908301906140fd8183602088016140b3565b01949350505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b600081518084526141478160208601602086016140b3565b601f01601f19169290920160200192915050565b600081518084526020808501808196508360051b8101915082860160005b858110156141a357828403895261419184835161412f565b98850198935090840190600101614179565b5091979650505050505050565b60006060820186835260206060818501528186835260808501905060808760051b86010192508760005b8881101561424957868503607f190183528135368b9003601e1901811261420057600080fd5b8a0184810190356001600160401b0381111561421b57600080fd5b80360382131561422a57600080fd5b614235878284614106565b9650505091830191908301906001016141da565b505050508281036040840152613003818561415b565b60006001600160401b0382111561427857614278613d55565b5060051b60200190565b600082601f83011261429357600080fd5b81516142a1613f2282613edc565b8181528460208386010111156142b657600080fd5b6142c78260208301602087016140b3565b949350505050565b600060208083850312156142e257600080fd5b82516001600160401b03808211156142f957600080fd5b818501915085601f83011261430d57600080fd5b815161431b613f228261425f565b81815260059190911b8301840190848101908883111561433a57600080fd5b8585015b838110156143cd578051858111156143565760008081fd5b86016040818c03601f190181131561436e5760008081fd5b614376613db5565b89830151888111156143885760008081fd5b6143968e8c83870101614282565b8252509082015190878211156143ac5760008081fd5b6143ba8d8b84860101614282565b818b01528552505091860191860161433e565b5098975050505050505050565b6000815160e084526143ef60e085018261412f565b905060208301518482036020860152614408828261412f565b91505060408301516001600160401b038082166040870152606085015191508583036060870152614439838361412f565b9250608085015191508583036080870152614454838361412f565b92508060a08601511660a0870152505060c083015184820360c0860152612800828261412f565b60808152600061448e60808301866143da565b90506144b06020830185805182526020908101516001600160a01b0316910152565b826060830152949350505050565b6000600182016144d0576144d0613d2c565b5060010190565b60006144e5613f228461425f565b8381529050602080820190600585901b84018681111561450457600080fd5b845b8181101561453f5780356001600160401b038111156145255760008081fd5b61453189828901613f03565b855250928201928201614506565b505050509392505050565b6000612b213684846144d7565b80356125e681613b2c565b600082601f83011261457357600080fd5b612b21838335602085016144d7565b600060e0823603121561459457600080fd5b61459c613d93565b82356001600160401b03808211156145b357600080fd5b6145bf36838701613f03565b835260208501359150808211156145d557600080fd5b6145e136838701613f03565b60208401526145f260408601613f59565b604084015261460360608601614557565b606084015261461460808601613f59565b608084015260a085013591508082111561462d57600080fd5b5061463a36828601614562565b60a08301525061464c60c08401613f59565b60c082015292915050565b848152608060208201526000614670608083018661415b565b8281036040840152614682818661415b565b90508281036060840152613003818561412f565b6000815160e084526146ab60e085018261412f565b9050602083015184820360208601526146c4828261412f565b91505060408301516001600160401b03808216604087015260018060a01b03606086015116606087015280608086015116608087015260a0850151915085830360a0870152614713838361415b565b92508060c08601511660c087015250508091505092915050565b60006040808352845181828501526147486080850182614696565b9050602080870151603f198684030160608701528281518085528385019150838160051b860101848401935060005b828110156147c757868203601f190184528451805189845261479b8a85018261412f565b91880151848303858a01529190506147b3818361412f565b968801969588019593505050600101614777565b506001600160a01b038a16858a015296506147e192505050565b5050509392505050565b60008235607e19833603018112613ed257600080fd5b60008235605e19833603018112613ed257600080fd5b60006060828403121561482957600080fd5b614831613d6b565b905081356001600160401b038082111561484a57600080fd5b61485685838601613f70565b8352602084013591508082111561486c57600080fd5b5061487984828501613f03565b60208301525061488b60408301613f59565b604082015292915050565b6000606082360312156148a857600080fd5b6148b0613d6b565b82356001600160401b038111156148c657600080fd5b6148d236828601614817565b825250602083013560208201526040830135604082015280915050919050565b600081516060845261490760608501826143da565b905060208301518482036020860152614920828261412f565b9150506001600160401b0360408401511660408501528091505092915050565b60408152600061495360408301856148f2565b905060018060a01b03831660208301529392505050565b60006060823603121561497c57600080fd5b614984613d6b565b82356001600160401b0381111561499a57600080fd5b6148d236828601613f70565b6000602082840312156149b857600080fd5b81516001600160401b038111156149ce57600080fd5b6142c784828501614282565b6000602082840312156149ec57600080fd5b8151612b2181613b2c565b60408152600061495360408301856143da565b604081526000614a1d604083018661412f565b8281036020840152614a30818587614106565b9695505050505050565b60008082840360c0811215614a4e57600080fd5b83516001600160401b03811115614a6457600080fd5b614a7086828701614282565b93505060a0601f1982011215614a8557600080fd5b50614a8e613d6b565b6020840151815260408401516020820152614aac8560608601613e07565b6040820152809150509250929050565b602081526000612b21602083018461412f565b600061016c3683614817565b60808152600061448e60808301866148f2565b60808152600061448e6080830186614696565b60008851614b13818460208d016140b3565b885190830190614b27818360208d016140b3565b60c089811b6001600160c01b03199081169390920192835288811b8216600884015287901b1660108201528451614b658160188401602089016140b3565b8451910190614b7b8160188401602088016140b3565b016018019998505050505050505050565b60008351614b9e8184602088016140b3565b60c09390931b6001600160c01b0319169190920190815260080192915050565b60008851614bd0818460208d016140b3565b885190830190614be4818360208d016140b3565b60c089811b6001600160c01b03199081169390920192835288901b1660088201528551614c18816010840160208a016140b3565b8551910190614c2e8160108401602089016140b3565b8451910190614c448160108401602088016140b3565b016010019998505050505050505050565b600181815b80851115614c90578160001904821115614c7657614c76613d2c565b80851615614c8357918102915b93841c9390800290614c5a565b509250929050565b600082614ca75750600161016c565b81614cb45750600061016c565b8160018114614cca5760028114614cd457614cf0565b600191505061016c565b60ff841115614ce557614ce5613d2c565b50506001821b61016c565b5060208310610133831016604e8410600b8410161715614d13575081810a61016c565b614d1d8383614c55565b8060001904821115614d3157614d31613d2c565b029392505050565b6000612b218383614c98565b8082018082111561016c5761016c613d2c565b634e487b7160e01b600052601260045260246000fd5b600082614d7d57614d7d614d58565b500690565b600082614d9157614d91614d58565b50049056fea26469706673582212209cfacc48ea27d6e669c54fa6bd03b3260804fd2212e74b33613a4f918f8fb13a64736f6c63430008110033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106100885760003560e01c80639d38eb351161005b5780639d38eb35146100ef578063bb1689be14610102578063e407f86b14610115578063ee241c0d1461012857600080fd5b806301ffc9a71461008d578063089b174c146100b45780632e8f454b146100c957806372becccd146100dc575b600080fd5b6100a061009b366004613b02565b61013b565b604051901515815260200160405180910390f35b6100c76100c2366004613b5c565b610172565b005b6100c76100d7366004613b5c565b61071e565b6100c76100ea366004613bbd565b610cc8565b6100c76100fd366004613bbd565b611346565b6100c7610110366004613c02565b61193b565b6100c7610123366004613b5c565b611db4565b6100c7610136366004613c86565b612356565b60006001600160e01b031982166378a7182760e01b148061016c57506301ffc9a760e01b6001600160e01b03198316145b92915050565b816000816001600160a01b031663054f7d9c6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101d79190613cdc565b905060018160038111156101ed576101ed613cfd565b148061020a5750600381600381111561020857610208613cfd565b145b1561022857604051631c6d5f7760e31b815260040160405180910390fd5b60408051631a880a9360e01b8152602085013560048201529084013560248201526000906001600160a01b03861690631a880a93906044016020604051808303816000875af115801561027f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102a39190613d13565b6102ad9042613d42565b90506000856001600160a01b031663f3f480d96040518163ffffffff1660e01b8152600401602060405180830381865afa1580156102ef573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103139190613d13565b9050801580159061032357508181115b156103415760405163048c969960e01b815260040160405180910390fd5b6040805163a70a8c4760e01b8152602087013560048201529086013560248201526000906001600160a01b0388169063a70a8c47906044016060604051808303816000875af1158015610398573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103bc9190613e41565b60408101519091506103e1576040516353ae552b60e11b815260040160405180910390fd5b60006103ed8780613e5d565b9050905060005b818110156107135760006104088980613e5d565b8381811061041857610418613ea6565b905060200281019061042a9190613ebc565b6104339061406f565b8451909150610441826125b9565b6001600160401b03161115610469576040516348e8dd2f60e11b815260040160405180910390fd5b6000610474826125eb565b604051630da2fd1960e21b8152600481018290529091506000906001600160a01b038d169063368bf464906024016040805180830381865afa1580156104be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104e2919061407b565b60208101519091506001600160a01b03166105105760405163f058bfd960e01b815260040160405180910390fd5b604080516001808252818301909252600091816020015b60608152602001906001900390816105275790505090506040518060400160405280600f81526020016e52657175657374526563656970747360881b8152508360405160200161057991815260200190565b60408051601f198184030181529082905261059792916020016140d7565b6040516020818303038152906040528186815181106105b8576105b8613ea6565b6020026020010181905250600073d8e040255903d5534b41cc7b0b256f76dcdb343c631475ff4589604001518f80606001906105f49190613e5d565b866040518563ffffffff1660e01b815260040161061494939291906141b0565b600060405180830381865af4158015610631573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261065991908101906142cf565b60008151811061066b5761066b613ea6565b6020026020010151905080602001515160001461069b576040516309bde33960e01b815260040160405180910390fd5b6040516325a377d560e11b81526001600160a01b038f1690634b46efaa906106cb9088908790899060040161447b565b600060405180830381600087803b1580156106e557600080fd5b505af11580156106f9573d6000803e3d6000fd5b5050505050505050508061070c906144be565b90506103f4565b505050505050505050565b816000816001600160a01b031663054f7d9c6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561075f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107839190613cdc565b9050600181600381111561079957610799613cfd565b14806107b6575060038160038111156107b4576107b4613cfd565b145b156107d457604051631c6d5f7760e31b815260040160405180910390fd5b60408051631a880a9360e01b81526020850135600482015290840135602482015242906000906001600160a01b03871690631a880a93906044016020604051808303816000875af115801561082d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108519190613d13565b61085b9083613d42565b90506000866001600160a01b031663f3f480d96040518163ffffffff1660e01b8152600401602060405180830381865afa15801561089d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108c19190613d13565b905080158015906108d157508181115b156108ef5760405163048c969960e01b815260040160405180910390fd5b6040805163a70a8c4760e01b8152602088013560048201529087013560248201526000906001600160a01b0389169063a70a8c47906044016060604051808303816000875af1158015610946573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096a9190613e41565b6040015190508061098e576040516353ae552b60e11b815260040160405180910390fd5b600061099d6060890189613e5d565b9150600090506109ad8980613e5d565b6109b69161454a565b905060005b82811015610cbb5760006109d260608c018c613e5d565b838181106109e2576109e2613ea6565b90506020028101906109f49190613ebc565b6109fd90614582565b9050610a0881612604565b6001600160401b03168810610a3057604051631676f4b360e01b815260040160405180910390fd5b6000610a3b82612631565b604051630da2fd1960e21b8152600481018290529091506000906001600160a01b038f169063368bf464906024016040805180830381865afa158015610a85573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa9919061407b565b60208101519091506001600160a01b0316610ad75760405163f058bfd960e01b815260040160405180910390fd5b60006001600160a01b03168e6001600160a01b0316638856337e846040518263ffffffff1660e01b8152600401610b1091815260200190565b6040805180830381865afa158015610b2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b50919061407b565b602001516001600160a01b031614610b7b5760405163156a571760e11b815260040160405180910390fd5b600073d8e040255903d5534b41cc7b0b256f76dcdb343c6355028f6f89888760a0015187604051602001610bb191815260200190565b6040516020818303038152906040526040518563ffffffff1660e01b8152600401610bdf9493929190614657565b600060405180830381865af4158015610bfc573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610c2491908101906142cf565b9050600060405180604001604052808681526020018381525090508f6001600160a01b031663ff279b9882610c563390565b6040518363ffffffff1660e01b8152600401610c7392919061472d565b600060405180830381600087803b158015610c8d57600080fd5b505af1158015610ca1573d6000803e3d6000fd5b50505050505050505080610cb4906144be565b90506109bb565b5050505050505050505050565b816000816001600160a01b031663054f7d9c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d2d9190613cdc565b90506001816003811115610d4357610d43613cfd565b1480610d6057506003816003811115610d5e57610d5e613cfd565b145b15610d7e57604051631c6d5f7760e31b815260040160405180910390fd5b4260006001600160a01b038616631a880a93610d9a87806147eb565b60405160e083901b6001600160e01b03191681528135600482015260209091013560248201526044016020604051808303816000875af1158015610de2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e069190613d13565b610e109083613d42565b90506000866001600160a01b031663f3f480d96040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e52573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e769190613d13565b90508015801590610e8657508181115b15610ea45760405163048c969960e01b815260040160405180910390fd5b6000610eb36020880188613e5d565b905090506000816001600160401b03811115610ed157610ed1613d55565b604051908082528060200260200182016040528015610f1c57816020015b6040805160608101825260008082526020808301829052928201528252600019909201910181610eef5790505b50905060005b82811015611156576000610f3960208b018b613e5d565b83818110610f4957610f49613ea6565b9050602002810190610f5b9190614801565b610f6490614896565b9050610f738160000151612732565b6001600160401b03168710610f9b57604051631676f4b360e01b815260040160405180910390fd5b805151600090610faa906125eb565b604051630da2fd1960e21b8152600481018290529091506000906001600160a01b038e169063368bf464906024016040805180830381865afa158015610ff4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611018919061407b565b60208101519091506001600160a01b0316611046576040516309bde33960e01b815260040160405180910390fd5b60006001600160a01b03168d6001600160a01b0316638856337e61106d866000015161275f565b6040518263ffffffff1660e01b815260040161108b91815260200190565b6040805180830381865afa1580156110a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110cb919061407b565b602001516001600160a01b0316146110f65760405163156a571760e11b815260040160405180910390fd5b60405180606001604052808460400151815260200184602001518152602001611122856000015161275f565b81525085858151811061113757611137613ea6565b60200260200101819052505050508061114f906144be565b9050610f22565b5060006001600160a01b038a1663a70a8c476111728b806147eb565b60405160e083901b6001600160e01b03191681528135600482015260209091013560248201526044016060604051808303816000875af11580156111ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111de9190613e41565b60200151905080611202576040516353ae552b60e11b815260040160405180910390fd5b611266816112108b806147eb565b61121e906040810190613e5d565b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525087925061125d91508e9050806147eb565b606001356127c1565b611283576040516309bde33960e01b815260040160405180910390fd5b60005b83811015610cbb57600061129d60208c018c613e5d565b838181106112ad576112ad613ea6565b90506020028101906112bf9190614801565b6112c890614896565b90508b6001600160a01b031663ab013de182600001516112e53390565b6040518363ffffffff1660e01b8152600401611302929190614940565b600060405180830381600087803b15801561131c57600080fd5b505af1158015611330573d6000803e3d6000fd5b50505050508061133f906144be565b9050611286565b816000816001600160a01b031663054f7d9c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611387573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113ab9190613cdc565b905060018160038111156113c1576113c1613cfd565b14806113de575060038160038111156113dc576113dc613cfd565b145b156113fc57604051631c6d5f7760e31b815260040160405180910390fd5b4260006001600160a01b038616631a880a9361141887806147eb565b60405160e083901b6001600160e01b03191681528135600482015260209091013560248201526044016020604051808303816000875af1158015611460573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114849190613d13565b61148e9083613d42565b90506000866001600160a01b031663f3f480d96040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114f49190613d13565b9050801580159061150457508181115b156115225760405163048c969960e01b815260040160405180910390fd5b60006115316020880188613e5d565b905090506000816001600160401b0381111561154f5761154f613d55565b60405190808252806020026020018201604052801561159a57816020015b604080516060810182526000808252602080830182905292820152825260001990920191018161156d5790505b50905060005b828110156117a15760006115b760208b018b613e5d565b838181106115c7576115c7613ea6565b90506020028101906115d99190614801565b6115e29061496a565b90506116598b6001600160a01b031663f437bc596040518163ffffffff1660e01b8152600401600060405180830381865afa158015611625573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261164d91908101906149a6565b825160200151906127d9565b611676576040516390d4c20960e01b815260040160405180910390fd5b8051611681906125b9565b6001600160401b031687106116a957604051631676f4b360e01b815260040160405180910390fd5b60006116b882600001516125eb565b604051630cb33d1f60e11b8152600481018290529091506000906001600160a01b038e16906319667a3e90602401602060405180830381865afa158015611703573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061172791906149da565b6001600160a01b03161461174e5760405163156a571760e11b815260040160405180910390fd5b604051806060016040528083604001518152602001836020015181526020018281525084848151811061178357611783613ea6565b602002602001018190525050508061179a906144be565b90506115a0565b5060006001600160a01b038a1663a70a8c476117bd8b806147eb565b60405160e083901b6001600160e01b03191681528135600482015260209091013560248201526044016060604051808303816000875af1158015611805573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118299190613e41565b6020015190508061184d576040516353ae552b60e11b815260040160405180910390fd5b61185b816112108b806147eb565b611878576040516309bde33960e01b815260040160405180910390fd5b60005b83811015610cbb57600061189260208c018c613e5d565b838181106118a2576118a2613ea6565b90506020028101906118b49190614801565b6118bd9061496a565b90508b6001600160a01b031663b85e6fbb82600001516118da3390565b6040518363ffffffff1660e01b81526004016118f79291906149f7565b600060405180830381600087803b15801561191157600080fd5b505af1158015611925573d6000803e3d6000fd5b505050505080611934906144be565b905061187b565b826000816001600160a01b031663054f7d9c6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561197c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119a09190613cdc565b905060018160038111156119b6576119b6613cfd565b14806119d3575060038160038111156119d1576119d1613cfd565b145b156119f157604051631c6d5f7760e31b815260040160405180910390fd5b6000856001600160a01b0316639a8425bc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a559190613d13565b611a5f9042613d42565b9050856001600160a01b031663d40784c76040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ac39190613d13565b8110611ae25760405163040dc5c360e41b815260040160405180910390fd5b600080876001600160a01b0316632476132b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b23573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b4791906149da565b6001600160a01b0316637d755598896001600160a01b031663bbad99d46040518163ffffffff1660e01b8152600401600060405180830381865afa158015611b93573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611bbb91908101906149a6565b89896040518463ffffffff1660e01b8152600401611bdb93929190614a0a565b6000604051808303816000875af1158015611bfa573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611c229190810190614a3a565b604051630b4974cf60e41b815291935091506001600160a01b0389169063b4974cf090611c53908590600401614abc565b600060405180830381600087803b158015611c6d57600080fd5b505af1158015611c81573d6000803e3d6000fd5b50508251604051634e04afc360e11b8152600093506001600160a01b038c169250639c095f8691611cb89160040190815260200190565b602060405180830381865afa158015611cd5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cf99190613d13565b90508015801590611d0d5750808260200151115b156107135760408051808201825283518152602080850151818301908152858401518451632acf7f4f60e11b81528451600482015291516024830152805160448301529182015160648201529201516084830152906001600160a01b038b169063559efe9e9060a401600060405180830381600087803b158015611d9057600080fd5b505af1158015611da4573d6000803e3d6000fd5b5050505050505050505050505050565b816000816001600160a01b031663054f7d9c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611df5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e199190613cdc565b90506001816003811115611e2f57611e2f613cfd565b1480611e4c57506003816003811115611e4a57611e4a613cfd565b145b15611e6a57604051631c6d5f7760e31b815260040160405180910390fd5b60408051631a880a9360e01b8152602085013560048201529084013560248201526000906001600160a01b03861690631a880a93906044016020604051808303816000875af1158015611ec1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ee59190613d13565b611eef9042613d42565b90506000856001600160a01b031663f3f480d96040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f559190613d13565b90508015801590611f6557508181115b15611f835760405163048c969960e01b815260040160405180910390fd5b6040805163a70a8c4760e01b8152602087013560048201529086013560248201526000906001600160a01b0388169063a70a8c47906044016060604051808303816000875af1158015611fda573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ffe9190613e41565b6040810151909150612023576040516353ae552b60e11b815260040160405180910390fd5b600061202f8780613e5d565b9050905060005b8181101561071357600061204a8980613e5d565b8381811061205a5761205a613ea6565b905060200281019061206c9190614801565b61207590614acf565b845190915061208382612732565b6001600160401b031611156120ab576040516348e8dd2f60e11b815260040160405180910390fd5b60006120b68261275f565b604051632211f1dd60e01b8152600481018290529091506000906001600160a01b038d1690632211f1dd906024016040805180830381865afa158015612100573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612124919061407b565b60208101519091506001600160a01b03166121525760405163f058bfd960e01b815260040160405180910390fd5b604080516001808252818301909252600091816020015b60608152602001906001900390816121695790505090506040518060400160405280601081526020016f526573706f6e7365526563656970747360801b815250836040516020016121bc91815260200190565b60408051601f19818403018152908290526121da92916020016140d7565b6040516020818303038152906040528186815181106121fb576121fb613ea6565b6020026020010181905250600073d8e040255903d5534b41cc7b0b256f76dcdb343c631475ff4589604001518f80606001906122379190613e5d565b866040518563ffffffff1660e01b815260040161225794939291906141b0565b600060405180830381865af4158015612274573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261229c91908101906142cf565b6000815181106122ae576122ae613ea6565b602002602001015190508060200151516000146122de576040516309bde33960e01b815260040160405180910390fd5b604051630446fc4760e01b81526001600160a01b038f1690630446fc479061230e90889087908990600401614adb565b600060405180830381600087803b15801561232857600080fd5b505af115801561233c573d6000803e3d6000fd5b5050505050505050508061234f906144be565b9050612036565b816000816001600160a01b031663054f7d9c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612397573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123bb9190613cdc565b905060018160038111156123d1576123d1613cfd565b14806123ee575060038160038111156123ec576123ec613cfd565b145b1561240c57604051631c6d5f7760e31b815260040160405180910390fd5b60006124188480613e5d565b915042905060005b828110156125b05760006124348780613e5d565b8381811061244457612444613ea6565b90506020028101906124569190613ebc565b61245f90614582565b9050600061246c82612631565b604051630da2fd1960e21b8152600481018290529091506000906001600160a01b038b169063368bf464906024016040805180830381865afa1580156124b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124da919061407b565b60208101519091506001600160a01b0316612508576040516309bde33960e01b815260040160405180910390fd5b8461251284612604565b6001600160401b0316111561253a576040516348e8dd2f60e11b815260040160405180910390fd5b60405163017d055b60e11b81526001600160a01b038b16906302fa0ab69061256a90869085908790600401614aee565b600060405180830381600087803b15801561258457600080fd5b505af1158015612598573d6000803e3d6000fd5b50505050505050806125a9906144be565b9050612420565b50505050505050565b60008160a001516001600160401b03166000036125de57506001600160401b03919050565b5060a0015190565b919050565b60006125f682612809565b805190602001209050919050565b600081608001516001600160401b031660000361262957506001600160401b03919050565b506080015190565b6040805160208101909152600080825260a083015151909190825b818110156126a857828560a00151828151811061266b5761266b613ea6565b60200260200101516040516020016126849291906140d7565b604051602081830303815290604052925080806126a0906144be565b91505061264c565b508360000151846020015185604001518660c00151876080015188606001516040516020016126ef919060609190911b6bffffffffffffffffffffffff1916815260140190565b60408051601f19818403018152908290526127139695949392918990602001614b01565b6040516020818303038152906040528051906020012092505050919050565b600081604001516001600160401b031660000361275757506001600160401b03919050565b506040015190565b600061276e8260000151612809565b60208084015160408086015190516127869301614b8c565b60408051601f19818403018152908290526127a492916020016140d7565b604051602081830303815290604052805190602001209050919050565b60006127ce84848461285a565b909414949350505050565b600081518351146127ec5750600061016c565b825160208381018281209186019283209091145b95945050505050565b60608160000151826020015183604001518460a00151856060015186608001518760c001516040516020016128449796959493929190614bbe565b6040516020818303038152906040529050919050565b600081600114801561286d575082516001145b801561289757508260008151811061288757612887613ea6565b6020026020010151602001516000145b156128c257826000815181106128af576128af613ea6565b6020026020010151604001519050612b21565b60006128cd83612b28565b90506000815190506000604051806040016040528060008152602001836001600160401b0381111561290157612901613d55565b60405190808252806020026020018201604052801561292a578160200160208202803683370190505b509052604080518082019091526000808252602082018a905291925090805b84811015612a7057600086828151811061296557612965613ea6565b6020026020010151905080600261297c9190614d39565b6129869084614d45565b6040805160008082526020820190925291945090816129cd565b60408051606081018252600080825260208083018290529282015282526000199092019101816129a05790505b508b51909150156129e7576129e28b85612bcb565b9b5090505b8051600003612a1b57845160208601515103612a04575050612a70565b612a1686612a1187612dca565b612e01565b612a66565b80516001148015612a2a575081155b15612a5757612a168682600081518110612a4657612a46613ea6565b602002602001015160400151612e01565b612a6686612a11838886612e31565b5050600101612949565b5082516000190183525b825115612afa576000612a8c8461300e565b90506000612a998561300e565b855160010186526040805160208101859052908101829052909150606001604051602081830303815290604052805190602001208560200151866000015181518110612ae757612ae7613ea6565b6020026020010181815250505050612a7a565b8260200151600081518110612b1157612b11613ea6565b6020026020010151955050505050505b9392505050565b6040805181815261082081018252606091906000908260208201610800803683370190505090506000845b83821015612baf578015612baf576000612b6c82613046565b905080848481518110612b8157612b81613ea6565b6020908102919091010152612b97816002614d39565b612ba19083613d42565b915082600101925050612b53565b6000612bbb8386613d42565b8451038452509195945050505050565b606080600080855190505b80821015612c1557858281518110612bf057612bf0613ea6565b602002602001015160200151851115612c155781612c0d816144be565b925050612bd6565b60008215612c235782612c26565b60005b90506000816001600160401b03811115612c4257612c42613d55565b604051908082528060200260200182016040528015612c8d57816020015b6040805160608101825260008082526020808301829052928201528252600019909201910181612c605790505b5090506000612c9c8385613d42565b6001600160401b03811115612cb357612cb3613d55565b604051908082528060200260200182016040528015612cfe57816020015b6040805160608101825260008082526020808301829052928201528252600019909201910181612cd15790505b5082519091506000905b80821015612d58578a8281518110612d2257612d22613ea6565b6020026020010151848381518110612d3c57612d3c613ea6565b602002602001018190525081612d51906144be565b9150612d08565b60005b86831015612db6578b8381518110612d7557612d75613ea6565b6020026020010151848281518110612d8f57612d8f613ea6565b602002602001018190525082612da4906144be565b9250612daf816144be565b9050612d5b565b5092975090955050505050505b9250929050565b6000808260200151836000015181518110612de757612de7613ea6565b602090810291909101015183516001019093525090919050565b808260200151836000015181518110612e1c57612e1c613ea6565b60209081029190910101525080516001019052565b6000606080612e3f866130da565b925090506000846001600160401b03811115612e5d57612e5d613d55565b604051908082528060200260200182016040528015612e9057816020015b6060815260200190600190039081612e7b5790505b50905060005b85811015612ff8576000612eaa8288613d42565b612eb5906002614d39565b905080855103612ec55750612ff8565b6000612ed086613258565b90506000612ede828861335a565b8051909150806001600160401b03811115612efb57612efb613d55565b604051908082528060200260200182016040528015612f4057816020015b6040805180820190915260008082526020820152815260200190600190039081612f195790505b50868681518110612f5357612f53613ea6565b602002602001018190525060005b81811015612fdd576040518060400160405280848381518110612f8657612f86613ea6565b60200260200101518152602001612f9c8e612dca565b815250878781518110612fb157612fb1613ea6565b60200260200101518281518110612fca57612fca613ea6565b6020908102919091010152600101612f61565b50612fe78361347c565b975084600101945050505050612e96565b50613003818361358f565b979650505050505050565b600080826020015183600001518151811061302b5761302b613ea6565b60209081029190910101518351600019019093525090919050565b600080608083901c1561305b57608092831c92015b604083901c1561306d57604092831c92015b602083901c1561307f57602092831c92015b601083901c1561309157601092831c92015b600883901c156130a357600892831c92015b600483901c156130b557600492831c92015b600283901c156130c757600292831c92015b600183901c1561016c5760010192915050565b606080600080845190506000816001600160401b038111156130fe576130fe613d55565b60405190808252806020026020018201604052801561314357816020015b604080518082019091526000808252602082015281526020019060019003908161311c5790505b5090506000826001600160401b0381111561316057613160613d55565b604051908082528060200260200182016040528015613189578160200160208202803683370190505b5090505b8284101561324c5760405180604001604052808886815181106131b2576131b2613ea6565b60200260200101516000015181526020018886815181106131d5576131d5613ea6565b6020026020010151604001518152508285815181106131f6576131f6613ea6565b602002602001018190525086848151811061321357613213613ea6565b60200260200101516000015181858151811061323157613231613ea6565b6020908102919091010152613245846144be565b935061318d565b90969095509350505050565b80516060906000816001600160401b0381111561327757613277613d55565b6040519080825280602002602001820160405280156132a0578160200160208202803683370190505b50905060005b828110156133525760008582815181106132c2576132c2613ea6565b6020026020010151905080600003613302576132df816001614d45565b8383815181106132f1576132f1613ea6565b602002602001018181525050613349565b61330d600282614d6e565b60000361331f576132df816001614d45565b61332a600182613d42565b83838151811061333c5761333c613ea6565b6020026020010181815250505b506001016132a6565b509392505050565b81518151606091906000826001600160401b0381111561337c5761337c613d55565b6040519080825280602002602001820160405280156133a5578160200160208202803683370190505b5090506000805b8481101561345e576000805b8581101561340a578881815181106133d2576133d2613ea6565b60200260200101518a84815181106133ec576133ec613ea6565b602002602001015103613402576001915061340a565b6001016133b8565b50806134555788828151811061342257613422613ea6565b602002602001015184848151811061343c5761343c613ea6565b602090810291909101015282613451816144be565b9350505b506001016133ac565b50600061346b8286613d42565b835103835250909695505050505050565b80516060906000816001600160401b0381111561349b5761349b613d55565b6040519080825280602002602001820160405280156134c4578160200160208202803683370190505b5090506000805b8381101561357357600060028783815181106134e9576134e9613ea6565b60200260200101516134fb9190614d82565b905060008311801561352f57508084613515600186613d42565b8151811061352557613525613ea6565b6020026020010151145b1561353a5750613561565b8084848151811061354d5761354d613ea6565b602002602001018181525050826001019250505b8061356b816144be565b9150506134cb565b5060006135808285613d42565b83510383525090949350505050565b604080516000808252602082019092528190816135ce565b60408051808201909152600080825260208201528152602001906001900390816135a75790505b5090506135f583856000815181106135e8576135e8613ea6565b60200260200101516138c2565b8460008151811061360857613608613ea6565b6020908102919091010152835160005b8181101561388a57604080516000808252602082019092528161365d565b60408051808201909152600080825260208201528152602001906001900390816136365790505b509050835160000361368a5786828151811061367b5761367b613ea6565b602002602001015190506136b0565b6136ad87838151811061369f5761369f613ea6565b6020026020010151856138c2565b90505b6136bc81516002613ace565b6001600160401b038111156136d3576136d3613d55565b60405190808252806020026020018201604052801561371857816020015b60408051808201909152600080825260208201528152602001906001900390816136f15790505b508151909450600090815b818110156138735781613737826001614d45565b106137ab57600084828151811061375057613750613ea6565b6020026020010151905061378285838151811061376f5761376f613ea6565b6020026020010151600001516002613af6565b81528751819089908690811061379a5761379a613ea6565b602002602001018190525050613861565b60408051808201909152600080825260208201526137d485838151811061376f5761376f613ea6565b81528451613833908690849081106137ee576137ee613ea6565b602002602001015160200151868460016138089190614d45565b8151811061381857613818613ea6565b60200260200101516020015160009182526020526040902090565b60208201528751819089908690811061384e5761384e613ea6565b6020908102919091010152506001909201915b61386c600282614d45565b9050613723565b505050508080613882906144be565b915050613618565b50815160011461389957600080fd5b816000815181106138ac576138ac613ea6565b6020026020010151602001519250505092915050565b8151815160609160009182918291826138db8284614d45565b90506000816001600160401b038111156138f7576138f7613d55565b60405190808252806020026020018201604052801561393c57816020015b60408051808201909152600080825260208201528152602001906001900390816139155790505b5090505b838710801561394e57508286105b15613a235788868151811061396557613965613ea6565b6020026020010151600001518a888151811061398357613983613ea6565b60200260200101516000015110156139dc578987815181106139a7576139a7613ea6565b60200260200101518186815181106139c1576139c1613ea6565b60209081029190910101526001968701969490940193613940565b8886815181106139ee576139ee613ea6565b6020026020010151818681518110613a0857613a08613ea6565b60209081029190910101526001958601959490940193613940565b83871015613a7257898781518110613a3d57613a3d613ea6565b6020026020010151818681518110613a5757613a57613ea6565b60209081029190910101526001968701969490940193613a23565b82861015613ac157888681518110613a8c57613a8c613ea6565b6020026020010151818681518110613aa657613aa6613ea6565b60209081029190910101526001958601959490940193613a72565b9998505050505050505050565b600080613adb8385614d82565b9050613ae78385614d6e565b15612b21576001019392505050565b6000612b218284614d82565b600060208284031215613b1457600080fd5b81356001600160e01b031981168114612b2157600080fd5b6001600160a01b0381168114613b4157600080fd5b50565b600060808284031215613b5657600080fd5b50919050565b60008060408385031215613b6f57600080fd5b8235613b7a81613b2c565b915060208301356001600160401b03811115613b9557600080fd5b613ba185828601613b44565b9150509250929050565b600060408284031215613b5657600080fd5b60008060408385031215613bd057600080fd5b8235613bdb81613b2c565b915060208301356001600160401b03811115613bf657600080fd5b613ba185828601613bab565b600080600060408486031215613c1757600080fd5b8335613c2281613b2c565b925060208401356001600160401b0380821115613c3e57600080fd5b818601915086601f830112613c5257600080fd5b813581811115613c6157600080fd5b876020828501011115613c7357600080fd5b6020830194508093505050509250925092565b60008060408385031215613c9957600080fd5b8235613ca481613b2c565b915060208301356001600160401b03811115613cbf57600080fd5b830160208186031215613cd157600080fd5b809150509250929050565b600060208284031215613cee57600080fd5b815160048110612b2157600080fd5b634e487b7160e01b600052602160045260246000fd5b600060208284031215613d2557600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561016c5761016c613d2c565b634e487b7160e01b600052604160045260246000fd5b604051606081016001600160401b0381118282101715613d8d57613d8d613d55565b60405290565b60405160e081016001600160401b0381118282101715613d8d57613d8d613d55565b604080519081016001600160401b0381118282101715613d8d57613d8d613d55565b604051601f8201601f191681016001600160401b0381118282101715613dff57613dff613d55565b604052919050565b600060608284031215613e1957600080fd5b613e21613d6b565b905081518152602082015160208201526040820151604082015292915050565b600060608284031215613e5357600080fd5b612b218383613e07565b6000808335601e19843603018112613e7457600080fd5b8301803591506001600160401b03821115613e8e57600080fd5b6020019150600581901b3603821315612dc357600080fd5b634e487b7160e01b600052603260045260246000fd5b6000823560de19833603018112613ed257600080fd5b9190910192915050565b60006001600160401b03821115613ef557613ef5613d55565b50601f01601f191660200190565b600082601f830112613f1457600080fd5b8135613f27613f2282613edc565b613dd7565b818152846020838601011115613f3c57600080fd5b816020850160208301376000918101602001919091529392505050565b80356001600160401b03811681146125e657600080fd5b600060e08284031215613f8257600080fd5b613f8a613d93565b905081356001600160401b0380821115613fa357600080fd5b613faf85838601613f03565b83526020840135915080821115613fc557600080fd5b613fd185838601613f03565b6020840152613fe260408501613f59565b60408401526060840135915080821115613ffb57600080fd5b61400785838601613f03565b6060840152608084013591508082111561402057600080fd5b61402c85838601613f03565b608084015261403d60a08501613f59565b60a084015260c084013591508082111561405657600080fd5b5061406384828501613f03565b60c08301525092915050565b600061016c3683613f70565b60006040828403121561408d57600080fd5b614095613db5565b8251815260208301516140a781613b2c565b60208201529392505050565b60005b838110156140ce5781810151838201526020016140b6565b50506000910152565b600083516140e98184602088016140b3565b8351908301906140fd8183602088016140b3565b01949350505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b600081518084526141478160208601602086016140b3565b601f01601f19169290920160200192915050565b600081518084526020808501808196508360051b8101915082860160005b858110156141a357828403895261419184835161412f565b98850198935090840190600101614179565b5091979650505050505050565b60006060820186835260206060818501528186835260808501905060808760051b86010192508760005b8881101561424957868503607f190183528135368b9003601e1901811261420057600080fd5b8a0184810190356001600160401b0381111561421b57600080fd5b80360382131561422a57600080fd5b614235878284614106565b9650505091830191908301906001016141da565b505050508281036040840152613003818561415b565b60006001600160401b0382111561427857614278613d55565b5060051b60200190565b600082601f83011261429357600080fd5b81516142a1613f2282613edc565b8181528460208386010111156142b657600080fd5b6142c78260208301602087016140b3565b949350505050565b600060208083850312156142e257600080fd5b82516001600160401b03808211156142f957600080fd5b818501915085601f83011261430d57600080fd5b815161431b613f228261425f565b81815260059190911b8301840190848101908883111561433a57600080fd5b8585015b838110156143cd578051858111156143565760008081fd5b86016040818c03601f190181131561436e5760008081fd5b614376613db5565b89830151888111156143885760008081fd5b6143968e8c83870101614282565b8252509082015190878211156143ac5760008081fd5b6143ba8d8b84860101614282565b818b01528552505091860191860161433e565b5098975050505050505050565b6000815160e084526143ef60e085018261412f565b905060208301518482036020860152614408828261412f565b91505060408301516001600160401b038082166040870152606085015191508583036060870152614439838361412f565b9250608085015191508583036080870152614454838361412f565b92508060a08601511660a0870152505060c083015184820360c0860152612800828261412f565b60808152600061448e60808301866143da565b90506144b06020830185805182526020908101516001600160a01b0316910152565b826060830152949350505050565b6000600182016144d0576144d0613d2c565b5060010190565b60006144e5613f228461425f565b8381529050602080820190600585901b84018681111561450457600080fd5b845b8181101561453f5780356001600160401b038111156145255760008081fd5b61453189828901613f03565b855250928201928201614506565b505050509392505050565b6000612b213684846144d7565b80356125e681613b2c565b600082601f83011261457357600080fd5b612b21838335602085016144d7565b600060e0823603121561459457600080fd5b61459c613d93565b82356001600160401b03808211156145b357600080fd5b6145bf36838701613f03565b835260208501359150808211156145d557600080fd5b6145e136838701613f03565b60208401526145f260408601613f59565b604084015261460360608601614557565b606084015261461460808601613f59565b608084015260a085013591508082111561462d57600080fd5b5061463a36828601614562565b60a08301525061464c60c08401613f59565b60c082015292915050565b848152608060208201526000614670608083018661415b565b8281036040840152614682818661415b565b90508281036060840152613003818561412f565b6000815160e084526146ab60e085018261412f565b9050602083015184820360208601526146c4828261412f565b91505060408301516001600160401b03808216604087015260018060a01b03606086015116606087015280608086015116608087015260a0850151915085830360a0870152614713838361415b565b92508060c08601511660c087015250508091505092915050565b60006040808352845181828501526147486080850182614696565b9050602080870151603f198684030160608701528281518085528385019150838160051b860101848401935060005b828110156147c757868203601f190184528451805189845261479b8a85018261412f565b91880151848303858a01529190506147b3818361412f565b968801969588019593505050600101614777565b506001600160a01b038a16858a015296506147e192505050565b5050509392505050565b60008235607e19833603018112613ed257600080fd5b60008235605e19833603018112613ed257600080fd5b60006060828403121561482957600080fd5b614831613d6b565b905081356001600160401b038082111561484a57600080fd5b61485685838601613f70565b8352602084013591508082111561486c57600080fd5b5061487984828501613f03565b60208301525061488b60408301613f59565b604082015292915050565b6000606082360312156148a857600080fd5b6148b0613d6b565b82356001600160401b038111156148c657600080fd5b6148d236828601614817565b825250602083013560208201526040830135604082015280915050919050565b600081516060845261490760608501826143da565b905060208301518482036020860152614920828261412f565b9150506001600160401b0360408401511660408501528091505092915050565b60408152600061495360408301856148f2565b905060018060a01b03831660208301529392505050565b60006060823603121561497c57600080fd5b614984613d6b565b82356001600160401b0381111561499a57600080fd5b6148d236828601613f70565b6000602082840312156149b857600080fd5b81516001600160401b038111156149ce57600080fd5b6142c784828501614282565b6000602082840312156149ec57600080fd5b8151612b2181613b2c565b60408152600061495360408301856143da565b604081526000614a1d604083018661412f565b8281036020840152614a30818587614106565b9695505050505050565b60008082840360c0811215614a4e57600080fd5b83516001600160401b03811115614a6457600080fd5b614a7086828701614282565b93505060a0601f1982011215614a8557600080fd5b50614a8e613d6b565b6020840151815260408401516020820152614aac8560608601613e07565b6040820152809150509250929050565b602081526000612b21602083018461412f565b600061016c3683614817565b60808152600061448e60808301866148f2565b60808152600061448e6080830186614696565b60008851614b13818460208d016140b3565b885190830190614b27818360208d016140b3565b60c089811b6001600160c01b03199081169390920192835288811b8216600884015287901b1660108201528451614b658160188401602089016140b3565b8451910190614b7b8160188401602088016140b3565b016018019998505050505050505050565b60008351614b9e8184602088016140b3565b60c09390931b6001600160c01b0319169190920190815260080192915050565b60008851614bd0818460208d016140b3565b885190830190614be4818360208d016140b3565b60c089811b6001600160c01b03199081169390920192835288901b1660088201528551614c18816010840160208a016140b3565b8551910190614c2e8160108401602089016140b3565b8451910190614c448160108401602088016140b3565b016010019998505050505050505050565b600181815b80851115614c90578160001904821115614c7657614c76613d2c565b80851615614c8357918102915b93841c9390800290614c5a565b509250929050565b600082614ca75750600161016c565b81614cb45750600061016c565b8160018114614cca5760028114614cd457614cf0565b600191505061016c565b60ff841115614ce557614ce5613d2c565b50506001821b61016c565b5060208310610133831016604e8410600b8410161715614d13575081810a61016c565b614d1d8383614c55565b8060001904821115614d3157614d31613d2c565b029392505050565b6000612b218383614c98565b8082018082111561016c5761016c613d2c565b634e487b7160e01b600052601260045260246000fd5b600082614d7d57614d7d614d58565b500690565b600082614d9157614d91614d58565b50049056fea26469706673582212209cfacc48ea27d6e669c54fa6bd03b3260804fd2212e74b33613a4f918f8fb13a64736f6c63430008110033
Loading...
Loading
[ Download: CSV Export ]
[ 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.