Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
Latest 25 from a total of 12,296 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Handle Consensus | 6551413 | 499 days ago | IN | 0 ETH | 0.010208656509 | ||||
Handle Consensus | 6551221 | 499 days ago | IN | 0 ETH | 0.010817916606 | ||||
Handle Consensus | 6551026 | 499 days ago | IN | 0 ETH | 0.010047886729 | ||||
Handle Consensus | 6550843 | 499 days ago | IN | 0 ETH | 0.00884445846 | ||||
Handle Consensus | 6550633 | 499 days ago | IN | 0 ETH | 0.008599418673 | ||||
Handle Consensus | 6550453 | 499 days ago | IN | 0 ETH | 0.007671184244 | ||||
Handle Consensus | 6550258 | 499 days ago | IN | 0 ETH | 0.007197599533 | ||||
Handle Consensus | 6550081 | 499 days ago | IN | 0 ETH | 0.007394066754 | ||||
Handle Consensus | 6549871 | 499 days ago | IN | 0 ETH | 0.00824032259 | ||||
Handle Consensus | 6549673 | 499 days ago | IN | 0 ETH | 0.009665510975 | ||||
Handle Consensus | 6549496 | 499 days ago | IN | 0 ETH | 0.009203799497 | ||||
Handle Consensus | 6549301 | 499 days ago | IN | 0 ETH | 0.007029983405 | ||||
Handle Consensus | 6549103 | 500 days ago | IN | 0 ETH | 0.007526437429 | ||||
Handle Consensus | 6548908 | 500 days ago | IN | 0 ETH | 0.008400821217 | ||||
Handle Consensus | 6548716 | 500 days ago | IN | 0 ETH | 0.008022138983 | ||||
Handle Consensus | 6548533 | 500 days ago | IN | 0 ETH | 0.007497225551 | ||||
Handle Consensus | 6548338 | 500 days ago | IN | 0 ETH | 0.007236929079 | ||||
Handle Consensus | 6548146 | 500 days ago | IN | 0 ETH | 0.007329719453 | ||||
Handle Consensus | 6547951 | 500 days ago | IN | 0 ETH | 0.007500470373 | ||||
Handle Consensus | 6547756 | 500 days ago | IN | 0 ETH | 0.008545926255 | ||||
Handle Consensus | 6547576 | 500 days ago | IN | 0 ETH | 0.009806003775 | ||||
Handle Consensus | 6547393 | 500 days ago | IN | 0 ETH | 0.008548497375 | ||||
Handle Consensus | 6547183 | 500 days ago | IN | 0 ETH | 0.00893569009 | ||||
Handle Consensus | 6546991 | 500 days ago | IN | 0 ETH | 0.00939939006 | ||||
Handle Consensus | 6546793 | 500 days ago | IN | 0 ETH | 0.007648510106 |
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
3954522 | 560 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)
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.17; import "solidity-merkle-trees/MerkleMountainRange.sol"; import "solidity-merkle-trees/MerklePatricia.sol"; import "openzeppelin/utils/Context.sol"; import "ismp/IConsensusClient.sol"; import "ismp/IHandler.sol"; import "ismp/IIsmpHost.sol"; contract HandlerV1 is IHandler, Context { using Bytes for bytes; modifier notFrozen(IIsmpHost host) { require(!host.frozen(), "IHandler: frozen"); _; } // Storage prefix for request receipts in pallet-ismp bytes private constant REQUEST_COMMITMENT_STORAGE_PREFIX = hex"103895530afb23bb607661426d55eb8b0484aecefe882c3ce64e6f82507f715a"; event StateMachineUpdated(uint256 stateMachineId, uint256 height); /** * @dev Handle incoming consensus messages * @param host - Ismp host * @param proof - consensus proof */ function handleConsensus(IIsmpHost host, bytes memory proof) external notFrozen(host) { require( (host.timestamp() - host.consensusUpdateTime()) > host.challengePeriod(), "IHandler: still in challenge period" ); // not today, time traveling validators require( (host.timestamp() - host.consensusUpdateTime()) < host.unStakingPeriod() || _msgSender() == host.admin(), "IHandler: still in challenge period" ); (bytes memory verifiedState, IntermediateState memory intermediate) = IConsensusClient(host.consensusClient()).verifyConsensus(host.consensusState(), proof); host.storeConsensusState(verifiedState); host.storeConsensusUpdateTime(host.timestamp()); if (intermediate.height > host.latestStateMachineHeight()) { StateMachineHeight memory stateMachineHeight = StateMachineHeight({stateMachineId: intermediate.stateMachineId, height: intermediate.height}); host.storeStateMachineCommitment(stateMachineHeight, intermediate.commitment); host.storeStateMachineCommitmentUpdateTime(stateMachineHeight, host.timestamp()); host.storeLatestStateMachineHeight(stateMachineHeight.height); // todo: enforce challenge period emit StateMachineUpdated({ stateMachineId: stateMachineHeight.stateMachineId, height: stateMachineHeight.height }); } } /** * @dev check request proofs, message delay and timeouts, then dispatch post requests to modules * @param host - Ismp host * @param request - batch post requests */ function handlePostRequests(IIsmpHost host, PostRequestMessage memory request) external notFrozen(host) { uint256 delay = host.timestamp() - host.stateMachineCommitmentUpdateTime(request.proof.height); require(delay > host.challengePeriod(), "IHandler: still in challenge period"); uint256 requestsLen = request.requests.length; MmrLeaf[] memory leaves = new MmrLeaf[](requestsLen); for (uint256 i = 0; i < requestsLen; i++) { PostRequestLeaf memory leaf = request.requests[i]; require(leaf.request.dest.equals(host.host()), "IHandler: Invalid request destination"); require( leaf.request.timeoutTimestamp == 0 || leaf.request.timeoutTimestamp > host.timestamp(), "IHandler: Request timed out" ); bytes32 commitment = Message.hash(leaf.request); require(!host.requestReceipts(commitment), "IHandler: Duplicate request"); leaves[i] = MmrLeaf(leaf.kIndex, leaf.index, commitment); } bytes32 root = host.stateMachineCommitment(request.proof.height).overlayRoot; require(root != bytes32(0), "IHandler: Proof height not found!"); require( MerkleMountainRange.VerifyProof(root, request.proof.multiproof, leaves, request.proof.leafCount), "IHandler: Invalid request proofs" ); for (uint256 i = 0; i < requestsLen; i++) { PostRequestLeaf memory leaf = request.requests[i]; host.dispatchIncoming(leaf.request); } } /** * @dev check response proofs, message delay and timeouts, then dispatch post responses to modules * @param host - Ismp host * @param response - batch post responses */ function handlePostResponses(IIsmpHost host, PostResponseMessage memory response) external notFrozen(host) { uint256 delay = host.timestamp() - host.stateMachineCommitmentUpdateTime(response.proof.height); require(delay > host.challengePeriod(), "IHandler: still in challenge period"); uint256 responsesLength = response.responses.length; MmrLeaf[] memory leaves = new MmrLeaf[](responsesLength); for (uint256 i = 0; i < responsesLength; i++) { PostResponseLeaf memory leaf = response.responses[i]; require(leaf.response.request.source.equals(host.host()), "IHandler: Invalid response destination"); bytes32 requestCommitment = Message.hash(leaf.response.request); require(host.requestCommitments(requestCommitment), "IHandler: Unknown request"); bytes32 responseCommitment = Message.hash(leaf.response); require(!host.responseCommitments(responseCommitment), "IHandler: Duplicate Post response"); leaves[i] = MmrLeaf(leaf.kIndex, leaf.index, responseCommitment); } bytes32 root = host.stateMachineCommitment(response.proof.height).overlayRoot; require(root != bytes32(0), "IHandler: Proof height not found!"); require( MerkleMountainRange.VerifyProof(root, response.proof.multiproof, leaves, response.proof.leafCount), "IHandler: Invalid response proofs" ); for (uint256 i = 0; i < responsesLength; i++) { PostResponseLeaf memory leaf = response.responses[i]; host.dispatchIncoming(leaf.response); } } /** * @dev check timeout proofs then dispatch to modules * @param host - Ismp host * @param message - batch post request timeouts */ function handlePostTimeouts(IIsmpHost host, PostTimeoutMessage memory message) external notFrozen(host) { // fetch the state commitment StateCommitment memory state = host.stateMachineCommitment(message.height); uint256 timeoutsLength = message.timeouts.length; for (uint256 i = 0; i < timeoutsLength; i++) { PostRequest memory request = message.timeouts[i]; require( request.timeoutTimestamp != 0 && state.timestamp > request.timeoutTimestamp, "Request not timed out" ); bytes32 requestCommitment = Message.hash(request); require(host.requestCommitments(requestCommitment), "IHandler: Unknown request"); bytes[] memory keys = new bytes[](1); keys[i] = bytes.concat(REQUEST_COMMITMENT_STORAGE_PREFIX, bytes.concat(requestCommitment)); StorageValue memory entry = MerklePatricia.VerifySubstrateProof(state.stateRoot, message.proof, keys)[0]; require(entry.value.equals(new bytes(0)), "IHandler: Invalid non-membership proof"); host.dispatchIncoming(PostTimeout(request)); } } /** * @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 notFrozen(host) { uint256 delay = host.timestamp() - host.stateMachineCommitmentUpdateTime(message.height); require(delay > host.challengePeriod(), "IHandler: still in challenge period"); StateCommitment memory stateCommitment = host.stateMachineCommitment(message.height); bytes32 root = stateCommitment.stateRoot; require(root != bytes32(0), "IHandler: Proof height not found!"); uint256 responsesLength = message.requests.length; bytes[] memory proof = message.proof; for (uint256 i = 0; i < responsesLength; i++) { GetRequest memory request = message.requests[i]; require(request.source.equals(host.host()), "IHandler: Invalid GET response destination"); bytes32 requestCommitment = Message.hash(request); require(host.requestCommitments(requestCommitment), "IHandler: Unknown GET request"); require( request.timeoutTimestamp == 0 || request.timeoutTimestamp > host.timestamp(), "IHandler: GET request timed out" ); StorageValue[] memory values = MerklePatricia.ReadChildProofCheck(root, proof, request.keys, bytes.concat(requestCommitment)); GetResponse memory response = GetResponse({request: request, values: values}); require(!host.responseCommitments(Message.hash(response)), "IHandler: Duplicate GET response"); host.dispatchIncoming(response); } } /** * @dev dispatch to modules * @param host - Ismp host * @param message - batch get request timeouts */ function handleGetTimeouts(IIsmpHost host, GetTimeoutMessage memory message) external notFrozen(host) { uint256 timeoutsLength = message.timeouts.length; for (uint256 i = 0; i < timeoutsLength; i++) { GetRequest memory request = message.timeouts[i]; bytes32 requestCommitment = Message.hash(request); require(host.requestCommitments(requestCommitment), "IHandler: Unknown request"); require( request.timeoutTimestamp != 0 && host.timestamp() > request.timeoutTimestamp, "IHandler: GET request not timed out" ); host.dispatchIncoming(request); } } }
// SPDX-License-Identifier: Apache2 pragma solidity ^0.8.17; import "./MerkleMultiProof.sol"; import "openzeppelin/utils/math/Math.sol"; /// @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; } /** * @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 provides root node function VerifyProof(bytes32 root, bytes32[] memory proof, MmrLeaf[] memory leaves, uint256 mmrSize) public 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) public 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 = 0; for (uint256 p = 0; p < length; p++) { 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 { 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 = 0; uint256 current = leavesLength; for (; i < maxSubtrees; i++) { if (current == 0) { break; } uint256 log = Math.log2(current); indices[i] = log; current = current - 2 ** log; } // 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 = 0; i < height; i++) { 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 = 0; j < length; j++) { layers[i][j] = Node(diff[j], next(proofIter)); } current_layer = parentIndices(siblings); } 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 = 0; for (uint256 i = 0; i < length; i++) { bool found = false; for (uint256 j = 0; j < rightLength; j++) { if (left[i] == right[j]) { found = true; break; } } if (!found) { diff[d] = left[i]; d++; } } // 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 = 0; i < length; i++) { 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; } } 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 = 0; for (uint256 i = 0; 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 = 0; 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 meountain 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 = 0; 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 = 0; uint256 leftLength = left.length; while (i < leftLength) { left[i] = leaves[i]; ++i; } uint256 j = 0; 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"; // 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 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 libraries in solidity can only have constant variables /// @dev MAX_TRIE_DEPTH, we don't explore deeply nested trie keys. uint256 internal constant MAX_TRIE_DEPTH = 50; /** * @notice Verifies 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)); // worst case scenario, so we avoid unbounded loops for (uint256 j = 0; j < MAX_TRIE_DEPTH; j++) { NodeHandle memory nextNode; if (TrieDB.isLeaf(node)) { Leaf memory leaf = 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)); // worst case scenario, so we avoid unbounded loops for (uint256 j = 0; j < MAX_TRIE_DEPTH; j++) { NodeHandle memory nextNode; if (TrieDB.isLeaf(node)) { Leaf memory leaf = EthereumTrieDB.decodeLeaf(node); // Let's retrieve the offset to be used uint256 offset = keyNibbles.offset % 2 == 0 ? keyNibbles.offset / 2 : keyNibbles.offset / 2 + 1; // Let's cut the key passed as input keyNibbles = NibbleSlice(NibbleSliceOps.bytesSlice(keyNibbles.data, offset), 0); if (NibbleSliceOps.eq(leaf.key, keyNibbles)) { 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 keyNibbles = NibbleSlice( NibbleSliceOps.bytesSlice(keyNibbles.data, NibbleSliceOps.len(extension.key)), 0 ); nextNode = extension.node; } else { break; } } else if (TrieDB.isBranch(node)) { Branch memory branch = EthereumTrieDB.decodeBranch(node); if (NibbleSliceOps.isEmpty(keyNibbles)) { if (Option.isSome(branch.value)) { 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; } }
// 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: UNLICENSED pragma solidity 0.8.17; import "solidity-merkle-trees/MerklePatricia.sol"; // 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; // merkle mountain range commitment to all ismp requests & response. bytes32 overlayRoot; // state root for processing timeouts. 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; } struct IntermediateState { // the state machine identifier uint256 stateMachineId; // height of this state machine uint256 height; // state commitment StateCommitment commitment; } interface IConsensusClient { /// Verify the consensus proof and return the new trusted consensus state and any intermediate states finalized /// by this consensus proof. function verifyConsensus(bytes memory trustedState, bytes memory proof) external returns (bytes memory, IntermediateState memory); }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.17; import "./IIsmpHost.sol"; import "./IIsmp.sol"; interface IHandler { /** * @dev Handle incoming consensus messages * @param host - Ismp host * @param proof - consensus proof */ function handleConsensus(IIsmpHost host, bytes memory proof) external; /** * @dev check request proofs, message delay and timeouts, then dispatch post requests to modules * @param host - Ismp host * @param request - batch post requests */ function handlePostRequests(IIsmpHost host, PostRequestMessage memory request) external; /** * @dev check response proofs, message delay and timeouts, then dispatch post responses to modules * @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 handlePostTimeouts(IIsmpHost host, PostTimeoutMessage memory message) external; /** * @dev dispatch to modules * @param host - Ismp host * @param message - batch get request timeouts */ function handleGetTimeouts(IIsmpHost host, GetTimeoutMessage memory message) external; }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.17; import {StateCommitment, StateMachineHeight} from "./IConsensusClient.sol"; import {IIsmp, PostRequest, PostResponse, GetResponse, PostTimeout, GetRequest} from "./IIsmp.sol"; struct BridgeParams { address admin; address consensus; address handler; uint256 challengePeriod; uint256 unstakingPeriod; uint256 defaultTimeout; } interface IIsmpHost is IIsmp { /** * @return the host admin */ function admin() external returns (address); /** * @return the host state machine id */ function host() external returns (bytes memory); /** * @return the host timestamp */ function timestamp() external returns (uint256); /** * @return the `frozen` status */ function frozen() external returns (bool); /** * @param height - state machine height * @return the state commitment at `height` */ function stateMachineCommitment(StateMachineHeight memory height) external 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); /** * @dev Should return a handle to the consensus client based on the id * @return the consensus client contract */ function consensusClient() external returns (address); /** * @return the last updated time of the consensus client */ function consensusUpdateTime() external returns (uint256); /** * @return the latest state machine height */ function latestStateMachineHeight() external returns (uint256); /** * @return the state of the consensus client */ function consensusState() external returns (bytes memory); /** * @param commitment - commitment to the request * @return existence status of an incoming request commitment */ function requestReceipts(bytes32 commitment) external returns (bool); /** * @param commitment - commitment to the response * @return existence status of an incoming response commitment */ function responseReceipts(bytes32 commitment) external returns (bool); /** * @param commitment - commitment to the request * @return existence status of an outgoing request commitment */ function requestCommitments(bytes32 commitment) external returns (bool); /** * @param commitment - commitment to the response * @return existence status of an outgoing response commitment */ function responseCommitments(bytes32 commitment) external returns (bool); /** * @return the challenge period */ function challengePeriod() external returns (uint256); /** * @return the unstaking period */ function unStakingPeriod() external returns (uint256); /** * @dev Store an encoded consensus state * @param state new consensus state */ function storeConsensusState(bytes memory state) external; /** * @dev Updates bridge params * @param params new bridge params */ function setBridgeParams(BridgeParams memory params) external; /** * @dev Store the timestamp when the consensus client was updated * @param timestamp - new timestamp */ function storeConsensusUpdateTime(uint256 timestamp) external; /** * @dev Store the latest state machine height * @param height State Machine Height */ function storeLatestStateMachineHeight(uint256 height) 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 Store the timestamp when the state machine was updated * @param height state machine height * @param timestamp new timestamp */ function storeStateMachineCommitmentUpdateTime(StateMachineHeight memory height, uint256 timestamp) external; /** * @dev Dispatch an incoming request to destination module * @param request - post request */ function dispatchIncoming(PostRequest memory request) external; /** * @dev Dispatch an incoming post response to source module * @param response - post response */ function dispatchIncoming(PostResponse memory response) external; /** * @dev Dispatch an incoming get response to source module * @param response - get response */ function dispatchIncoming(GetResponse memory response) external; /** * @dev Dispatch an incoming get timeout to source module * @param timeout - get timeout */ function dispatchIncoming(GetRequest memory timeout) external; /** * @dev Dispatch an incoming post timeout to source module * @param timeout - post timeout */ function dispatchIncoming(PostTimeout memory timeout) external; }
// SPDX-License-Identifier: Apache2 pragma solidity ^0.8.17; import "openzeppelin/utils/math/Math.sol"; /// @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 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; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.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) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1, "Math: mulDiv overflow"); /////////////////////////////////////////////// // 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 256, 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 << 3) < value ? 1 : 0); } } }
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(); //Remove the first byte, which is the prefix and not present in the user provided key extension.key = NibbleSlice(Bytes.substr(decoded[0].toBytes(), 1), 0); extension.node = NodeHandle(true, Bytes.toBytes32(data), false, new bytes(0)); return extension; } function decodeBranch(NodeKind memory node) 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); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.17; import "solidity-merkle-trees/MerklePatricia.sol"; import {StateMachineHeight} from "./IConsensusClient.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; // gas limit for executing this request on destination & its response (if any) on the source. uint64 gaslimit; } 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 bytes 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; // gas limit for executing this request on destination & its response (if any) on the source. uint64 gaslimit; } 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; } // 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 PostTimeoutMessage { // requests which have timed-out PostRequest[] 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; } // An object for dispatching post requests to the IsmpDispatcher struct DispatchPost { // bytes representation of the destination chain bytes dest; // the destination module bytes to; // the request body bytes body; // timeout for this request in seconds uint64 timeout; // gas limit for executing this request on destination & its response (if any) on the source. uint64 gaslimit; } // An object for dispatching get requests to the IsmpDispatcher struct DispatchGet { // bytes representation of the destination chain 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; // gas limit for executing this request on destination & its response (if any) on the source. uint64 gaslimit; } // The core ISMP API, IIsmpModules use this interface to send outgoing get/post requests & responses interface IIsmp { /** * @dev Dispatch a post request to the ISMP router. * @param request - post request */ function dispatch(DispatchPost memory request) external; /** * @dev Dispatch a get request to the ISMP router. * @param request - get request */ function dispatch(DispatchGet memory request) external; /** * @dev Provide a response to a previously received request. * @param response - post response */ function dispatch(PostResponse memory response) external; } library Message { function hash(PostResponse memory res) internal pure returns (bytes32) { return keccak256( abi.encodePacked( res.request.source, res.request.dest, res.request.nonce, res.request.timeoutTimestamp, res.request.body, res.request.from, res.request.to, res.response ) ); } function hash(PostRequest memory req) internal pure returns (bytes32) { return keccak256( abi.encodePacked( req.source, req.dest, req.nonce, req.timeoutTimestamp, req.from, req.to, req.body, req.gaslimit ) ); } 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, req.from, keysEncoding, req.gaslimit ) ); } function hash(GetResponse memory res) internal pure returns (bytes32) { bytes memory keysEncoding = abi.encode(res.request.keys); bytes memory preimage = abi.encodePacked( res.request.source, res.request.dest, res.request.nonce, res.request.height, res.request.timeoutTimestamp, res.request.from, keysEncoding, res.request.gaslimit ); uint256 len = res.values.length; for (uint256 i = 0; i < len; i++) { StorageValue memory entry = res.values[i]; preimage = bytes.concat(preimage, abi.encodePacked(entry.key, entry.value)); } return keccak256(preimage); } }
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; } }
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.9.0) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/Math.sol"; import "./math/SignedMath.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 `int256` to its ASCII `string` decimal representation. */ function toString(int256 value) internal pure returns (string memory) { return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value)))); } /** * @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); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return keccak256(bytes(a)) == keccak256(bytes(b)); } }
// 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)) } } } }
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: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.0; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } }
{ "remappings": [ "ismp/=lib/ismp-solidity/src/", "openzeppelin/=lib/openzeppelin-contracts/contracts/", "solidity-merkle-trees/=lib/solidity-merkle-trees/src/", "multi-chain-tokens/=lib/multi-chain-tokens/src/", "ds-test/=lib/forge-std/lib/ds-test/src/", "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/", "forge-std/=lib/forge-std/src/", "ismp-solidity/=lib/ismp-solidity/src/", "openzeppelin-contracts/=lib/openzeppelin-contracts/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "libraries": { "lib/ismp-solidity/src/StateMachine.sol": { "StateMachine": "0x7dfd0726095806c836d8698cf8ed54d00fa9fbcf" }, "lib/solidity-merkle-trees/src/MerkleMountainRange.sol": { "MerkleMountainRange": "0xc7dccd6ca30a7ab7df2e446a0181f16200f09302" }, "lib/solidity-merkle-trees/src/MerklePatricia.sol": { "MerklePatricia": "0x0e08d3edef6f0cdf458946a5b0e44ffad1a5cc33" }, "lib/solidity-merkle-trees/src/trie/ethereum/EthereumTrieDB.sol": { "EthereumTrieDB": "0x47b9159aa7e8256178b6f87b843c50d68c6cdfce" } } }
Contract ABI
API[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"stateMachineId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"height","type":"uint256"}],"name":"StateMachineUpdated","type":"event"},{"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":[{"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":"bytes","name":"from","type":"bytes"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"},{"internalType":"bytes[]","name":"keys","type":"bytes[]"},{"internalType":"uint64","name":"height","type":"uint64"},{"internalType":"uint64","name":"gaslimit","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":"uint64","name":"timeoutTimestamp","type":"uint64"},{"internalType":"bytes[]","name":"keys","type":"bytes[]"},{"internalType":"uint64","name":"height","type":"uint64"},{"internalType":"uint64","name":"gaslimit","type":"uint64"}],"internalType":"struct GetRequest[]","name":"timeouts","type":"tuple[]"}],"internalType":"struct GetTimeoutMessage","name":"message","type":"tuple"}],"name":"handleGetTimeouts","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":"uint64","name":"gaslimit","type":"uint64"}],"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":"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":"uint64","name":"gaslimit","type":"uint64"}],"internalType":"struct PostRequest","name":"request","type":"tuple"},{"internalType":"bytes","name":"response","type":"bytes"}],"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":"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":"uint64","name":"gaslimit","type":"uint64"}],"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 PostTimeoutMessage","name":"message","type":"tuple"}],"name":"handlePostTimeouts","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b50614031806100206000396000f3fe608060405234801561001057600080fd5b50600436106100625760003560e01c806320d71c7a14610067578063873ce1ce1461007c578063ac269bd61461008f578063bb1689be146100a2578063d95e4fbb146100b5578063fda626c3146100c8575b600080fd5b61007a610075366004612cdb565b6100db565b005b61007a61008a3660046130b4565b610819565b61007a61009d36600461316b565b610f43565b61007a6100b0366004613202565b6111e7565b61007a6100c3366004613251565b611a82565b61007a6100d6366004613378565b611f43565b81806001600160a01b031663054f7d9c6040518163ffffffff1660e01b81526004016020604051808303816000875af115801561011c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061014091906134d8565b156101665760405162461bcd60e51b815260040161015d90613501565b60405180910390fd5b815151604051631a880a9360e01b81526000916001600160a01b03861691631a880a93916101969160040161352b565b6020604051808303816000875af11580156101b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101d99190613542565b846001600160a01b031663b80777ea6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015610219573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061023d9190613542565b6102479190613571565b9050836001600160a01b031663f3f480d96040518163ffffffff1660e01b81526004016020604051808303816000875af1158015610289573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102ad9190613542565b81116102cb5760405162461bcd60e51b815260040161015d90613584565b6020830151516000816001600160401b038111156102eb576102eb612972565b60405190808252806020026020018201604052801561033657816020015b60408051606081018252600080825260208083018290529282015282526000199092019101816103095790505b50905060005b828110156105f95760008660200151828151811061035c5761035c6135c7565b602002602001015190506103db886001600160a01b031663f437bc596040518163ffffffff1660e01b81526004016000604051808303816000875af11580156103a9573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526103d1919081019061364e565b8251515190612698565b6104365760405162461bcd60e51b815260206004820152602660248201527f4948616e646c65723a20496e76616c696420726573706f6e73652064657374696044820152653730ba34b7b760d11b606482015260840161015d565b805151600090610445906126ca565b604051630da2fd1960e21b8152600481018290529091506001600160a01b038a169063368bf464906024016020604051808303816000875af115801561048f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104b391906134d8565b6104cf5760405162461bcd60e51b815260040161015d90613682565b60006104de8360000151612721565b604051632211f1dd60e01b8152600481018290529091506001600160a01b038b1690632211f1dd906024016020604051808303816000875af1158015610528573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061054c91906134d8565b156105a35760405162461bcd60e51b815260206004820152602160248201527f4948616e646c65723a204475706c696361746520506f737420726573706f6e736044820152606560f81b606482015260840161015d565b60405180606001604052808460400151815260200184602001518152602001828152508585815181106105d8576105d86135c7565b602002602001018190525050505080806105f1906136b9565b91505061033c565b5084515160405163a70a8c4760e01b81526000916001600160a01b0389169163a70a8c479161062a9160040161352b565b6060604051808303816000875af1158015610649573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061066d919061370c565b602001519050806106905760405162461bcd60e51b815260040161015d90613728565b85516020810151604091820151915163722e206d60e01b815273c7dccd6ca30a7ab7df2e446a0181f16200f093029263722e206d926106d59286928891600401613769565b602060405180830381865af41580156106f2573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061071691906134d8565b61076c5760405162461bcd60e51b815260206004820152602160248201527f4948616e646c65723a20496e76616c696420726573706f6e73652070726f6f666044820152607360f81b606482015260840161015d565b60005b8381101561080f5760008760200151828151811061078f5761078f6135c7565b60200260200101519050886001600160a01b0316638cf66b9282600001516040518263ffffffff1660e01b81526004016107c99190613916565b600060405180830381600087803b1580156107e357600080fd5b505af11580156107f7573d6000803e3d6000fd5b50505050508080610807906136b9565b91505061076f565b5050505050505050565b81806001600160a01b031663054f7d9c6040518163ffffffff1660e01b81526004016020604051808303816000875af115801561085a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061087e91906134d8565b1561089b5760405162461bcd60e51b815260040161015d90613501565b6020820151604051631a880a9360e01b81526000916001600160a01b03861691631a880a93916108cd9160040161352b565b6020604051808303816000875af11580156108ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109109190613542565b846001600160a01b031663b80777ea6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015610950573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109749190613542565b61097e9190613571565b9050836001600160a01b031663f3f480d96040518163ffffffff1660e01b81526004016020604051808303816000875af11580156109c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109e49190613542565b8111610a025760405162461bcd60e51b815260040161015d90613584565b602083015160405163a70a8c4760e01b81526000916001600160a01b0387169163a70a8c4791610a349160040161352b565b6060604051808303816000875af1158015610a53573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a77919061370c565b604081015190915080610a9c5760405162461bcd60e51b815260040161015d90613728565b604085015151855160005b82811015610f3857600088604001518281518110610ac757610ac76135c7565b60200260200101519050610b448a6001600160a01b031663f437bc596040518163ffffffff1660e01b81526004016000604051808303816000875af1158015610b14573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610b3c919081019061364e565b825190612698565b610ba35760405162461bcd60e51b815260206004820152602a60248201527f4948616e646c65723a20496e76616c69642047455420726573706f6e7365206460448201526932b9ba34b730ba34b7b760b11b606482015260840161015d565b6000610bae82612764565b604051630da2fd1960e21b8152600481018290529091506001600160a01b038c169063368bf464906024016020604051808303816000875af1158015610bf8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c1c91906134d8565b610c685760405162461bcd60e51b815260206004820152601d60248201527f4948616e646c65723a20556e6b6e6f776e204745542072657175657374000000604482015260640161015d565b60808201516001600160401b03161580610cf157508a6001600160a01b031663b80777ea6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015610cbd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ce19190613542565b82608001516001600160401b0316115b610d3d5760405162461bcd60e51b815260206004820152601f60248201527f4948616e646c65723a2047455420726571756573742074696d6564206f757400604482015260640161015d565b6000730e08d3edef6f0cdf458946a5b0e44ffad1a5cc336355028f6f88878660a0015186604051602001610d7391815260200190565b6040516020818303038152906040526040518563ffffffff1660e01b8152600401610da194939291906139a4565b600060405180830381865af4158015610dbe573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610de691908101906139ee565b60408051808201909152848152602081018290529091506001600160a01b038d16632211f1dd610e1583612836565b6040518263ffffffff1660e01b8152600401610e3391815260200190565b6020604051808303816000875af1158015610e52573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e7691906134d8565b15610ec35760405162461bcd60e51b815260206004820181905260248201527f4948616e646c65723a204475706c69636174652047455420726573706f6e7365604482015260640161015d565b60405163f073609160e01b81526001600160a01b038e169063f073609190610eef908490600401613bcb565b600060405180830381600087803b158015610f0957600080fd5b505af1158015610f1d573d6000803e3d6000fd5b50505050505050508080610f30906136b9565b915050610aa7565b505050505050505050565b81806001600160a01b031663054f7d9c6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015610f84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fa891906134d8565b15610fc55760405162461bcd60e51b815260040161015d90613501565b81515160005b818110156111e057600084600001518281518110610feb57610feb6135c7565b60200260200101519050600061100082612764565b604051630da2fd1960e21b8152600481018290529091506001600160a01b0388169063368bf464906024016020604051808303816000875af115801561104a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061106e91906134d8565b61108a5760405162461bcd60e51b815260040161015d90613682565b60808201516001600160401b031615801590611115575081608001516001600160401b0316876001600160a01b031663b80777ea6040518163ffffffff1660e01b81526004016020604051808303816000875af11580156110ef573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111139190613542565b115b61116d5760405162461bcd60e51b815260206004820152602360248201527f4948616e646c65723a204745542072657175657374206e6f742074696d6564206044820152621bdd5d60ea1b606482015260840161015d565b6040516384566a5d60e01b81526001600160a01b038816906384566a5d90611199908590600401613c71565b600060405180830381600087803b1580156111b357600080fd5b505af11580156111c7573d6000803e3d6000fd5b50505050505080806111d8906136b9565b915050610fcb565b5050505050565b81806001600160a01b031663054f7d9c6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015611228573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061124c91906134d8565b156112695760405162461bcd60e51b815260040161015d90613501565b826001600160a01b031663f3f480d96040518163ffffffff1660e01b81526004016020604051808303816000875af11580156112a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112cd9190613542565b836001600160a01b0316639a8425bc6040518163ffffffff1660e01b81526004016020604051808303816000875af115801561130d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113319190613542565b846001600160a01b031663b80777ea6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015611371573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113959190613542565b61139f9190613571565b116113bc5760405162461bcd60e51b815260040161015d90613584565b826001600160a01b031663d40784c76040518163ffffffff1660e01b81526004016020604051808303816000875af11580156113fc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114209190613542565b836001600160a01b0316639a8425bc6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015611460573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114849190613542565b846001600160a01b031663b80777ea6040518163ffffffff1660e01b81526004016020604051808303816000875af11580156114c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114e89190613542565b6114f29190613571565b10806115725750826001600160a01b031663f851a4406040518163ffffffff1660e01b81526004016020604051808303816000875af1158015611539573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061155d9190613c84565b6001600160a01b0316336001600160a01b0316145b61158e5760405162461bcd60e51b815260040161015d90613584565b600080846001600160a01b0316632476132b6040518163ffffffff1660e01b81526004016020604051808303816000875af11580156115d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115f59190613c84565b6001600160a01b0316637d755598866001600160a01b031663bbad99d46040518163ffffffff1660e01b81526004016000604051808303816000875af1158015611643573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261166b919081019061364e565b866040518363ffffffff1660e01b8152600401611689929190613ca1565b6000604051808303816000875af11580156116a8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526116d09190810190613ccf565b604051630b4974cf60e41b815291935091506001600160a01b0386169063b4974cf090611701908590600401613d51565b600060405180830381600087803b15801561171b57600080fd5b505af115801561172f573d6000803e3d6000fd5b50505050846001600160a01b031663d860cb47866001600160a01b031663b80777ea6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015611782573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117a69190613542565b6040518263ffffffff1660e01b81526004016117c491815260200190565b600060405180830381600087803b1580156117de57600080fd5b505af11580156117f2573d6000803e3d6000fd5b50505050846001600160a01b03166356b655976040518163ffffffff1660e01b81526004016020604051808303816000875af1158015611836573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061185a9190613542565b816020015111156111e05760408051808201825282518152602080840151818301908152848401518451632acf7f4f60e11b81528451600482015291516024830152805160448301529182015160648201529201516084830152906001600160a01b0387169063559efe9e9060a401600060405180830381600087803b1580156118e357600080fd5b505af11580156118f7573d6000803e3d6000fd5b50505050856001600160a01b03166314863dcb82886001600160a01b031663b80777ea6040518163ffffffff1660e01b81526004016020604051808303816000875af115801561194b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061196f9190613542565b6040516001600160e01b031960e085901b1681528251600482015260209092015160248301526044820152606401600060405180830381600087803b1580156119b757600080fd5b505af11580156119cb573d6000803e3d6000fd5b505050602082015160405163a0756ecd60e01b81526001600160a01b038916925063a0756ecd91611a029160040190815260200190565b600060405180830381600087803b158015611a1c57600080fd5b505af1158015611a30573d6000803e3d6000fd5b5050825160208401516040517ff12a80290a43822c9acabb2a766d41728f06fe4c0497e4a7bb3f54292e4cb0da9450611a729350918252602082015260400190565b60405180910390a1505050505050565b81806001600160a01b031663054f7d9c6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015611ac3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ae791906134d8565b15611b045760405162461bcd60e51b815260040161015d90613501565b602082015160405163a70a8c4760e01b81526000916001600160a01b0386169163a70a8c4791611b369160040161352b565b6060604051808303816000875af1158015611b55573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b79919061370c565b83515190915060005b81811015611f3b57600085600001518281518110611ba257611ba26135c7565b602002602001015190508060a001516001600160401b0316600014158015611bda57508060a001516001600160401b03168460000151115b611c1e5760405162461bcd60e51b815260206004820152601560248201527414995c5d595cdd081b9bdd081d1a5b5959081bdd5d605a1b604482015260640161015d565b6000611c29826126ca565b604051630da2fd1960e21b8152600481018290529091506001600160a01b0389169063368bf464906024016020604051808303816000875af1158015611c73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c9791906134d8565b611cb35760405162461bcd60e51b815260040161015d90613682565b604080516001808252818301909252600091816020015b6060815260200190600190039081611cca57505060408051808201825260208082527f103895530afb23bb607661426d55eb8b0484aecefe882c3ce64e6f82507f715a818301528251908101869052929350910160408051601f1981840301815290829052611d3c9291602001613d64565b604051602081830303815290604052818581518110611d5d57611d5d6135c7565b60200260200101819052506000730e08d3edef6f0cdf458946a5b0e44ffad1a5cc33631475ff4588604001518b60400151856040518463ffffffff1660e01b8152600401611dad93929190613d93565b600060405180830381865af4158015611dca573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611df291908101906139ee565b600081518110611e0457611e046135c7565b60200260200101519050611e6060006001600160401b03811115611e2a57611e2a612972565b6040519080825280601f01601f191660200182016040528015611e54576020820181803683370190505b50602083015190612698565b611ebb5760405162461bcd60e51b815260206004820152602660248201527f4948616e646c65723a20496e76616c6964206e6f6e2d6d656d6265727368697060448201526510383937b7b360d11b606482015260840161015d565b6040805160208101825285815290516312dde20360e11b81526001600160a01b038c16916325bbc40691611ef29190600401613dc8565b600060405180830381600087803b158015611f0c57600080fd5b505af1158015611f20573d6000803e3d6000fd5b50505050505050508080611f33906136b9565b915050611b82565b505050505050565b81806001600160a01b031663054f7d9c6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015611f84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fa891906134d8565b15611fc55760405162461bcd60e51b815260040161015d90613501565b815151604051631a880a9360e01b81526000916001600160a01b03861691631a880a9391611ff59160040161352b565b6020604051808303816000875af1158015612014573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120389190613542565b846001600160a01b031663b80777ea6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015612078573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061209c9190613542565b6120a69190613571565b9050836001600160a01b031663f3f480d96040518163ffffffff1660e01b81526004016020604051808303816000875af11580156120e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061210c9190613542565b811161212a5760405162461bcd60e51b815260040161015d90613584565b6020830151516000816001600160401b0381111561214a5761214a612972565b60405190808252806020026020018201604052801561219557816020015b60408051606081018252600080825260208083018290529282015282526000199092019101816121685790505b50905060005b8281101561248c576000866020015182815181106121bb576121bb6135c7565b6020026020010151905061223c886001600160a01b031663f437bc596040518163ffffffff1660e01b81526004016000604051808303816000875af1158015612208573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612230919081019061364e565b82516020015190612698565b6122965760405162461bcd60e51b815260206004820152602560248201527f4948616e646c65723a20496e76616c696420726571756573742064657374696e60448201526430ba34b7b760d91b606482015260840161015d565b805160a001516001600160401b031615806123215750876001600160a01b031663b80777ea6040518163ffffffff1660e01b81526004016020604051808303816000875af11580156122ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123109190613542565b815160a001516001600160401b0316115b61236d5760405162461bcd60e51b815260206004820152601b60248201527f4948616e646c65723a20526571756573742074696d6564206f75740000000000604482015260640161015d565b600061237c82600001516126ca565b604051630cb33d1f60e11b8152600481018290529091506001600160a01b038a16906319667a3e906024016020604051808303816000875af11580156123c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123ea91906134d8565b156124375760405162461bcd60e51b815260206004820152601b60248201527f4948616e646c65723a204475706c696361746520726571756573740000000000604482015260640161015d565b604051806060016040528083604001518152602001836020015181526020018281525084848151811061246c5761246c6135c7565b602002602001018190525050508080612484906136b9565b91505061219b565b5084515160405163a70a8c4760e01b81526000916001600160a01b0389169163a70a8c47916124bd9160040161352b565b6060604051808303816000875af11580156124dc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612500919061370c565b602001519050806125235760405162461bcd60e51b815260040161015d90613728565b85516020810151604091820151915163722e206d60e01b815273c7dccd6ca30a7ab7df2e446a0181f16200f093029263722e206d926125689286928891600401613769565b602060405180830381865af4158015612585573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125a991906134d8565b6125f55760405162461bcd60e51b815260206004820181905260248201527f4948616e646c65723a20496e76616c696420726571756573742070726f6f6673604482015260640161015d565b60005b8381101561080f57600087602001518281518110612618576126186135c7565b60200260200101519050886001600160a01b0316633b8c2bf782600001516040518263ffffffff1660e01b81526004016126529190613de3565b600060405180830381600087803b15801561266c57600080fd5b505af1158015612680573d6000803e3d6000fd5b50505050508080612690906136b9565b9150506125f8565b600081518351146126ab575060006126c4565b825160208381018281209186019283209091145b925050505b92915050565b805160208083015160408085015160a08601516060870151608088015160c089015160e08a01519551600099612704999098979101613df6565b604051602081830303815290604052805190602001209050919050565b8051805160208083015160408085015160a086015160c08701516060880151608090980151868a0151945160009961270499989596949593949093909101613e9e565b6040805160208101909152600080825260a083015151909190825b818110156127db57828560a00151828151811061279e5761279e6135c7565b60200260200101516040516020016127b7929190613d64565b604051602081830303815290604052925080806127d3906136b9565b91505061277f565b508360000151846020015185604001518660c0015187608001518860600151878a60e00151604051602001612817989796959493929190613f4c565b6040516020818303038152906040528051906020012092505050919050565b600080826000015160a001516040516020016128529190613fe8565b60408051601f19818403018152828252855180516020828101519483015160c08401516080850151606086015160e0909601519699506000986128a49895979596939592949193928b92909101613f4c565b60408051601f1981840301815291905260208501515190915060005b81811015612949576000866020015182815181106128e0576128e06135c7565b602002602001015190508381600001518260200151604051602001612906929190613d64565b60408051601f19818403018152908290526129249291602001613d64565b6040516020818303038152906040529350508080612941906136b9565b9150506128c0565b505080516020909101209392505050565b6001600160a01b038116811461296f57600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b03811182821017156129aa576129aa612972565b60405290565b604051606081016001600160401b03811182821017156129aa576129aa612972565b60405161010081016001600160401b03811182821017156129aa576129aa612972565b604051601f8201601f191681016001600160401b0381118282101715612a1d57612a1d612972565b604052919050565b600060408284031215612a3757600080fd5b612a3f612988565b9050813581526020820135602082015292915050565b60006001600160401b03821115612a6e57612a6e612972565b5060051b60200190565b600060808284031215612a8a57600080fd5b612a926129b0565b9050612a9e8383612a25565b815260408201356001600160401b03811115612ab957600080fd5b8201601f81018413612aca57600080fd5b80356020612adf612ada83612a55565b6129f5565b82815260059290921b83018101918181019087841115612afe57600080fd5b938201935b83851015612b1c57843582529382019390820190612b03565b808387015250505050506060820135604082015292915050565b60006001600160401b03821115612b4f57612b4f612972565b50601f01601f191660200190565b600082601f830112612b6e57600080fd5b8135612b7c612ada82612b36565b818152846020838601011115612b9157600080fd5b816020850160208301376000918101602001919091529392505050565b80356001600160401b0381168114612bc557600080fd5b919050565b60006101008284031215612bdd57600080fd5b612be56129d2565b905081356001600160401b0380821115612bfe57600080fd5b612c0a85838601612b5d565b83526020840135915080821115612c2057600080fd5b612c2c85838601612b5d565b6020840152612c3d60408501612bae565b60408401526060840135915080821115612c5657600080fd5b612c6285838601612b5d565b60608401526080840135915080821115612c7b57600080fd5b612c8785838601612b5d565b6080840152612c9860a08501612bae565b60a084015260c0840135915080821115612cb157600080fd5b50612cbe84828501612b5d565b60c083015250612cd060e08301612bae565b60e082015292915050565b60008060408385031215612cee57600080fd5b612cf8833561295a565b823591506001600160401b038060208501351115612d1557600080fd5b6020840135840160408187031215612d2c57600080fd5b612d34612988565b8282351115612d4257600080fd5b612d4f8783358401612a78565b81528260208301351115612d6257600080fd5b60208201358201915086601f830112612d7a57600080fd5b612d87612ada8335612a55565b82358082526020808301929160051b850101891015612da557600080fd5b602084015b6020853560051b860101811015612e9b578581351115612dc957600080fd5b601f196060823587018c0382011215612de157600080fd5b612de96129b0565b8760208435890101351115612dfd57600080fd5b823587016020810135016040818e0384011215612e1957600080fd5b612e21612988565b92508860208201351115612e3457600080fd5b612e468d602080840135840101612bca565b83528860408201351115612e5957600080fd5b612e6c8d60206040840135840101612b5d565b602084810191909152928252506040833588018181013583850152606001359082015284529283019201612daa565b506020830152509396939550929350505050565b600082601f830112612ec057600080fd5b81356020612ed0612ada83612a55565b82815260059290921b84018101918181019086841115612eef57600080fd5b8286015b84811015612f2e5780356001600160401b03811115612f125760008081fd5b612f208986838b0101612b5d565b845250918301918301612ef3565b509695505050505050565b600082601f830112612f4a57600080fd5b81356020612f5a612ada83612a55565b82815260059290921b84018101918181019086841115612f7957600080fd5b8286015b84811015612f2e5780356001600160401b0380821115612f9d5760008081fd5b90880190610100828b03601f1901811315612fb85760008081fd5b612fc06129d2565b8784013583811115612fd25760008081fd5b612fe08d8a83880101612b5d565b82525060408085013584811115612ff75760008081fd5b6130058e8b83890101612b5d565b8a840152506060613017818701612bae565b828401526080915081860135858111156130315760008081fd5b61303f8f8c838a0101612b5d565b82850152505060a0613052818701612bae565b8284015260c09150818601358581111561306c5760008081fd5b61307a8f8c838a0101612eaf565b82850152505060e0935061308f848601612bae565b9082015261309e848301612bae565b9281019290925250845250918301918301612f7d565b600080604083850312156130c757600080fd5b82356130d28161295a565b915060208301356001600160401b03808211156130ee57600080fd5b908401906080828703121561310257600080fd5b61310a6129b0565b82358281111561311957600080fd5b61312588828601612eaf565b8252506131358760208501612a25565b602082015260608301358281111561314c57600080fd5b61315888828601612f39565b6040830152508093505050509250929050565b6000806040838503121561317e57600080fd5b82356131898161295a565b915060208301356001600160401b03808211156131a557600080fd5b90840190602082870312156131b957600080fd5b6040516020810181811083821117156131d4576131d4612972565b6040528235828111156131e657600080fd5b6131f288828601612f39565b8252508093505050509250929050565b6000806040838503121561321557600080fd5b82356132208161295a565b915060208301356001600160401b0381111561323b57600080fd5b61324785828601612b5d565b9150509250929050565b6000806040838503121561326457600080fd5b823561326f8161295a565b91506020838101356001600160401b038082111561328c57600080fd5b90850190608082880312156132a057600080fd5b6132a86129b0565b8235828111156132b757600080fd5b8301601f810189136132c857600080fd5b80356132d6612ada82612a55565b81815260059190911b8201860190868101908b8311156132f557600080fd5b8784015b8381101561332d578035878111156133115760008081fd5b61331f8e8b83890101612bca565b8452509188019188016132f9565b508085525050505061334188858501612a25565b84820152606083013593508184111561335957600080fd5b61336588858501612eaf565b6040820152809450505050509250929050565b6000806040838503121561338b57600080fd5b82356133968161295a565b91506020838101356001600160401b03808211156133b357600080fd5b90850190604082880312156133c757600080fd5b6133cf612988565b8235828111156133de57600080fd5b6133ea89828601612a78565b82525083830135828111156133fe57600080fd5b80840193505087601f84011261341357600080fd5b8235613421612ada82612a55565b81815260059190911b8401850190858101908a83111561344057600080fd5b8686015b838110156134c15780358681111561345b57600080fd5b87016060818e03601f190112156134725760008081fd5b61347a6129b0565b898201358881111561348c5760008081fd5b61349a8f8c83860101612bca565b8252506040828101358b830152606090920135918101919091528352918701918701613444565b508087850152505050809450505050509250929050565b6000602082840312156134ea57600080fd5b815180151581146134fa57600080fd5b9392505050565b60208082526010908201526f24a430b7323632b91d10333937bd32b760811b604082015260600190565b8151815260208083015190820152604081016126c4565b60006020828403121561355457600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b818103818111156126c4576126c461355b565b60208082526023908201527f4948616e646c65723a207374696c6c20696e206368616c6c656e6765207065726040820152621a5bd960ea1b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b60005b838110156135f85781810151838201526020016135e0565b50506000910152565b600082601f83011261361257600080fd5b8151613620612ada82612b36565b81815284602083860101111561363557600080fd5b6136468260208301602087016135dd565b949350505050565b60006020828403121561366057600080fd5b81516001600160401b0381111561367657600080fd5b61364684828501613601565b60208082526019908201527f4948616e646c65723a20556e6b6e6f776e207265717565737400000000000000604082015260600190565b6000600182016136cb576136cb61355b565b5060010190565b6000606082840312156136e457600080fd5b6136ec6129b0565b905081518152602082015160208201526040820151604082015292915050565b60006060828403121561371e57600080fd5b6134fa83836136d2565b60208082526021908201527f4948616e646c65723a2050726f6f6620686569676874206e6f7420666f756e646040820152602160f81b606082015260800190565b600060808201868352602060808185015281875180845260a086019150828901935060005b818110156137aa5784518352938301939183019160010161378e565b505060409250848103838601528087518083528383019150838901925060005b818110156137f957835180518452858101518685015286015186840152928401926060909201916001016137ca565b50508094505050505082606083015295945050505050565b600081518084526138298160208601602086016135dd565b601f01601f19169290920160200192915050565b6000610100825181855261385382860182613811565b9150506020830151848203602086015261386d8282613811565b915050604083015161388a60408601826001600160401b03169052565b50606083015184820360608601526138a28282613811565b915050608083015184820360808601526138bc8282613811565b91505060a08301516138d960a08601826001600160401b03169052565b5060c083015184820360c08601526138f18282613811565b91505060e083015161390e60e08601826001600160401b03169052565b509392505050565b602081526000825160406020840152613932606084018261383d565b90506020840151601f198483030160408501526126bf8282613811565b600081518084526020808501808196508360051b8101915082860160005b85811015613997578284038952613985848351613811565b9885019893509084019060010161396d565b5091979650505050505050565b8481526080602082015260006139bd608083018661394f565b82810360408401526139cf818661394f565b905082810360608401526139e38185613811565b979650505050505050565b60006020808385031215613a0157600080fd5b82516001600160401b0380821115613a1857600080fd5b818501915085601f830112613a2c57600080fd5b8151613a3a612ada82612a55565b81815260059190911b83018401908481019088831115613a5957600080fd5b8585015b83811015613aec57805185811115613a755760008081fd5b86016040818c03601f1901811315613a8d5760008081fd5b613a95612988565b8983015188811115613aa75760008081fd5b613ab58e8c83870101613601565b825250908201519087821115613acb5760008081fd5b613ad98d8b84860101613601565b818b015285525050918601918601613a5d565b5098975050505050505050565b60006101008251818552613b0f82860182613811565b91505060208301518482036020860152613b298282613811565b9150506040830151613b4660408601826001600160401b03169052565b5060608301518482036060860152613b5e8282613811565b9150506080830151613b7b60808601826001600160401b03169052565b5060a083015184820360a0860152613b93828261394f565b91505060c0830151613bb060c08601826001600160401b03169052565b5060e083015161390e60e08601826001600160401b03169052565b60006020808352835160408083860152613be86060860183613af9565b83870151601f1987830381018489015281518084529294509085019184860190600581901b8601870160005b82811015613c62578488830301845285518051888452613c3689850182613811565b918b0151848303858d0152919050613c4e8183613811565b978b0197958b019593505050600101613c14565b509a9950505050505050505050565b6020815260006134fa6020830184613af9565b600060208284031215613c9657600080fd5b81516134fa8161295a565b604081526000613cb46040830185613811565b8281036020840152613cc68185613811565b95945050505050565b60008082840360c0811215613ce357600080fd5b83516001600160401b03811115613cf957600080fd5b613d0586828701613601565b93505060a0601f1982011215613d1a57600080fd5b50613d236129b0565b6020840151815260408401516020820152613d4185606086016136d2565b6040820152809150509250929050565b6020815260006134fa6020830184613811565b60008351613d768184602088016135dd565b835190830190613d8a8183602088016135dd565b01949350505050565b838152606060208201526000613dac606083018561394f565b8281036040840152613dbe818561394f565b9695505050505050565b6020815260008251602080840152613646604084018261383d565b6020815260006134fa602083018461383d565b60008951613e08818460208e016135dd565b895190830190613e1c818360208e016135dd565b60c08a811b6001600160c01b03199081169390920192835289901b811660088301528751613e51816010850160208c016135dd565b8751920191613e67816010850160208b016135dd565b8651920191613e7d816010850160208a016135dd565b60c09590951b16930160108101939093525050601801979650505050505050565b600089516020613eb18285838f016135dd565b8a5191840191613ec48184848f016135dd565b60c08b811b6001600160c01b0319908116949092019384528a901b1660088301528751613ef78160108501848c016135dd565b8751920191613f0c8160108501848b016135dd565b8651920191613f218160108501848a016135dd565b8551920191613f3681601085018489016135dd565b919091016010019b9a5050505050505050505050565b60008951613f5e818460208e016135dd565b895190830190613f72818360208e016135dd565b60c08a811b6001600160c01b03199081169390920192835289811b8216600884015288901b811660108301528651613fb1816018850160208b016135dd565b8651920191613fc7816018850160208a016135dd565b60c09590951b16930160188101939093525050602001979650505050505050565b6020815260006134fa602083018461394f56fea2646970667358221220f7655f63159e9b3a74f2aa456aba017ca61fbf2ebcdad44e0257eef9a5e4da3c64736f6c63430008110033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106100625760003560e01c806320d71c7a14610067578063873ce1ce1461007c578063ac269bd61461008f578063bb1689be146100a2578063d95e4fbb146100b5578063fda626c3146100c8575b600080fd5b61007a610075366004612cdb565b6100db565b005b61007a61008a3660046130b4565b610819565b61007a61009d36600461316b565b610f43565b61007a6100b0366004613202565b6111e7565b61007a6100c3366004613251565b611a82565b61007a6100d6366004613378565b611f43565b81806001600160a01b031663054f7d9c6040518163ffffffff1660e01b81526004016020604051808303816000875af115801561011c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061014091906134d8565b156101665760405162461bcd60e51b815260040161015d90613501565b60405180910390fd5b815151604051631a880a9360e01b81526000916001600160a01b03861691631a880a93916101969160040161352b565b6020604051808303816000875af11580156101b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101d99190613542565b846001600160a01b031663b80777ea6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015610219573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061023d9190613542565b6102479190613571565b9050836001600160a01b031663f3f480d96040518163ffffffff1660e01b81526004016020604051808303816000875af1158015610289573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102ad9190613542565b81116102cb5760405162461bcd60e51b815260040161015d90613584565b6020830151516000816001600160401b038111156102eb576102eb612972565b60405190808252806020026020018201604052801561033657816020015b60408051606081018252600080825260208083018290529282015282526000199092019101816103095790505b50905060005b828110156105f95760008660200151828151811061035c5761035c6135c7565b602002602001015190506103db886001600160a01b031663f437bc596040518163ffffffff1660e01b81526004016000604051808303816000875af11580156103a9573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526103d1919081019061364e565b8251515190612698565b6104365760405162461bcd60e51b815260206004820152602660248201527f4948616e646c65723a20496e76616c696420726573706f6e73652064657374696044820152653730ba34b7b760d11b606482015260840161015d565b805151600090610445906126ca565b604051630da2fd1960e21b8152600481018290529091506001600160a01b038a169063368bf464906024016020604051808303816000875af115801561048f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104b391906134d8565b6104cf5760405162461bcd60e51b815260040161015d90613682565b60006104de8360000151612721565b604051632211f1dd60e01b8152600481018290529091506001600160a01b038b1690632211f1dd906024016020604051808303816000875af1158015610528573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061054c91906134d8565b156105a35760405162461bcd60e51b815260206004820152602160248201527f4948616e646c65723a204475706c696361746520506f737420726573706f6e736044820152606560f81b606482015260840161015d565b60405180606001604052808460400151815260200184602001518152602001828152508585815181106105d8576105d86135c7565b602002602001018190525050505080806105f1906136b9565b91505061033c565b5084515160405163a70a8c4760e01b81526000916001600160a01b0389169163a70a8c479161062a9160040161352b565b6060604051808303816000875af1158015610649573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061066d919061370c565b602001519050806106905760405162461bcd60e51b815260040161015d90613728565b85516020810151604091820151915163722e206d60e01b815273c7dccd6ca30a7ab7df2e446a0181f16200f093029263722e206d926106d59286928891600401613769565b602060405180830381865af41580156106f2573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061071691906134d8565b61076c5760405162461bcd60e51b815260206004820152602160248201527f4948616e646c65723a20496e76616c696420726573706f6e73652070726f6f666044820152607360f81b606482015260840161015d565b60005b8381101561080f5760008760200151828151811061078f5761078f6135c7565b60200260200101519050886001600160a01b0316638cf66b9282600001516040518263ffffffff1660e01b81526004016107c99190613916565b600060405180830381600087803b1580156107e357600080fd5b505af11580156107f7573d6000803e3d6000fd5b50505050508080610807906136b9565b91505061076f565b5050505050505050565b81806001600160a01b031663054f7d9c6040518163ffffffff1660e01b81526004016020604051808303816000875af115801561085a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061087e91906134d8565b1561089b5760405162461bcd60e51b815260040161015d90613501565b6020820151604051631a880a9360e01b81526000916001600160a01b03861691631a880a93916108cd9160040161352b565b6020604051808303816000875af11580156108ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109109190613542565b846001600160a01b031663b80777ea6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015610950573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109749190613542565b61097e9190613571565b9050836001600160a01b031663f3f480d96040518163ffffffff1660e01b81526004016020604051808303816000875af11580156109c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109e49190613542565b8111610a025760405162461bcd60e51b815260040161015d90613584565b602083015160405163a70a8c4760e01b81526000916001600160a01b0387169163a70a8c4791610a349160040161352b565b6060604051808303816000875af1158015610a53573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a77919061370c565b604081015190915080610a9c5760405162461bcd60e51b815260040161015d90613728565b604085015151855160005b82811015610f3857600088604001518281518110610ac757610ac76135c7565b60200260200101519050610b448a6001600160a01b031663f437bc596040518163ffffffff1660e01b81526004016000604051808303816000875af1158015610b14573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610b3c919081019061364e565b825190612698565b610ba35760405162461bcd60e51b815260206004820152602a60248201527f4948616e646c65723a20496e76616c69642047455420726573706f6e7365206460448201526932b9ba34b730ba34b7b760b11b606482015260840161015d565b6000610bae82612764565b604051630da2fd1960e21b8152600481018290529091506001600160a01b038c169063368bf464906024016020604051808303816000875af1158015610bf8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c1c91906134d8565b610c685760405162461bcd60e51b815260206004820152601d60248201527f4948616e646c65723a20556e6b6e6f776e204745542072657175657374000000604482015260640161015d565b60808201516001600160401b03161580610cf157508a6001600160a01b031663b80777ea6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015610cbd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ce19190613542565b82608001516001600160401b0316115b610d3d5760405162461bcd60e51b815260206004820152601f60248201527f4948616e646c65723a2047455420726571756573742074696d6564206f757400604482015260640161015d565b6000730e08d3edef6f0cdf458946a5b0e44ffad1a5cc336355028f6f88878660a0015186604051602001610d7391815260200190565b6040516020818303038152906040526040518563ffffffff1660e01b8152600401610da194939291906139a4565b600060405180830381865af4158015610dbe573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610de691908101906139ee565b60408051808201909152848152602081018290529091506001600160a01b038d16632211f1dd610e1583612836565b6040518263ffffffff1660e01b8152600401610e3391815260200190565b6020604051808303816000875af1158015610e52573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e7691906134d8565b15610ec35760405162461bcd60e51b815260206004820181905260248201527f4948616e646c65723a204475706c69636174652047455420726573706f6e7365604482015260640161015d565b60405163f073609160e01b81526001600160a01b038e169063f073609190610eef908490600401613bcb565b600060405180830381600087803b158015610f0957600080fd5b505af1158015610f1d573d6000803e3d6000fd5b50505050505050508080610f30906136b9565b915050610aa7565b505050505050505050565b81806001600160a01b031663054f7d9c6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015610f84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fa891906134d8565b15610fc55760405162461bcd60e51b815260040161015d90613501565b81515160005b818110156111e057600084600001518281518110610feb57610feb6135c7565b60200260200101519050600061100082612764565b604051630da2fd1960e21b8152600481018290529091506001600160a01b0388169063368bf464906024016020604051808303816000875af115801561104a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061106e91906134d8565b61108a5760405162461bcd60e51b815260040161015d90613682565b60808201516001600160401b031615801590611115575081608001516001600160401b0316876001600160a01b031663b80777ea6040518163ffffffff1660e01b81526004016020604051808303816000875af11580156110ef573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111139190613542565b115b61116d5760405162461bcd60e51b815260206004820152602360248201527f4948616e646c65723a204745542072657175657374206e6f742074696d6564206044820152621bdd5d60ea1b606482015260840161015d565b6040516384566a5d60e01b81526001600160a01b038816906384566a5d90611199908590600401613c71565b600060405180830381600087803b1580156111b357600080fd5b505af11580156111c7573d6000803e3d6000fd5b50505050505080806111d8906136b9565b915050610fcb565b5050505050565b81806001600160a01b031663054f7d9c6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015611228573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061124c91906134d8565b156112695760405162461bcd60e51b815260040161015d90613501565b826001600160a01b031663f3f480d96040518163ffffffff1660e01b81526004016020604051808303816000875af11580156112a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112cd9190613542565b836001600160a01b0316639a8425bc6040518163ffffffff1660e01b81526004016020604051808303816000875af115801561130d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113319190613542565b846001600160a01b031663b80777ea6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015611371573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113959190613542565b61139f9190613571565b116113bc5760405162461bcd60e51b815260040161015d90613584565b826001600160a01b031663d40784c76040518163ffffffff1660e01b81526004016020604051808303816000875af11580156113fc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114209190613542565b836001600160a01b0316639a8425bc6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015611460573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114849190613542565b846001600160a01b031663b80777ea6040518163ffffffff1660e01b81526004016020604051808303816000875af11580156114c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114e89190613542565b6114f29190613571565b10806115725750826001600160a01b031663f851a4406040518163ffffffff1660e01b81526004016020604051808303816000875af1158015611539573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061155d9190613c84565b6001600160a01b0316336001600160a01b0316145b61158e5760405162461bcd60e51b815260040161015d90613584565b600080846001600160a01b0316632476132b6040518163ffffffff1660e01b81526004016020604051808303816000875af11580156115d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115f59190613c84565b6001600160a01b0316637d755598866001600160a01b031663bbad99d46040518163ffffffff1660e01b81526004016000604051808303816000875af1158015611643573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261166b919081019061364e565b866040518363ffffffff1660e01b8152600401611689929190613ca1565b6000604051808303816000875af11580156116a8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526116d09190810190613ccf565b604051630b4974cf60e41b815291935091506001600160a01b0386169063b4974cf090611701908590600401613d51565b600060405180830381600087803b15801561171b57600080fd5b505af115801561172f573d6000803e3d6000fd5b50505050846001600160a01b031663d860cb47866001600160a01b031663b80777ea6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015611782573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117a69190613542565b6040518263ffffffff1660e01b81526004016117c491815260200190565b600060405180830381600087803b1580156117de57600080fd5b505af11580156117f2573d6000803e3d6000fd5b50505050846001600160a01b03166356b655976040518163ffffffff1660e01b81526004016020604051808303816000875af1158015611836573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061185a9190613542565b816020015111156111e05760408051808201825282518152602080840151818301908152848401518451632acf7f4f60e11b81528451600482015291516024830152805160448301529182015160648201529201516084830152906001600160a01b0387169063559efe9e9060a401600060405180830381600087803b1580156118e357600080fd5b505af11580156118f7573d6000803e3d6000fd5b50505050856001600160a01b03166314863dcb82886001600160a01b031663b80777ea6040518163ffffffff1660e01b81526004016020604051808303816000875af115801561194b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061196f9190613542565b6040516001600160e01b031960e085901b1681528251600482015260209092015160248301526044820152606401600060405180830381600087803b1580156119b757600080fd5b505af11580156119cb573d6000803e3d6000fd5b505050602082015160405163a0756ecd60e01b81526001600160a01b038916925063a0756ecd91611a029160040190815260200190565b600060405180830381600087803b158015611a1c57600080fd5b505af1158015611a30573d6000803e3d6000fd5b5050825160208401516040517ff12a80290a43822c9acabb2a766d41728f06fe4c0497e4a7bb3f54292e4cb0da9450611a729350918252602082015260400190565b60405180910390a1505050505050565b81806001600160a01b031663054f7d9c6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015611ac3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ae791906134d8565b15611b045760405162461bcd60e51b815260040161015d90613501565b602082015160405163a70a8c4760e01b81526000916001600160a01b0386169163a70a8c4791611b369160040161352b565b6060604051808303816000875af1158015611b55573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b79919061370c565b83515190915060005b81811015611f3b57600085600001518281518110611ba257611ba26135c7565b602002602001015190508060a001516001600160401b0316600014158015611bda57508060a001516001600160401b03168460000151115b611c1e5760405162461bcd60e51b815260206004820152601560248201527414995c5d595cdd081b9bdd081d1a5b5959081bdd5d605a1b604482015260640161015d565b6000611c29826126ca565b604051630da2fd1960e21b8152600481018290529091506001600160a01b0389169063368bf464906024016020604051808303816000875af1158015611c73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c9791906134d8565b611cb35760405162461bcd60e51b815260040161015d90613682565b604080516001808252818301909252600091816020015b6060815260200190600190039081611cca57505060408051808201825260208082527f103895530afb23bb607661426d55eb8b0484aecefe882c3ce64e6f82507f715a818301528251908101869052929350910160408051601f1981840301815290829052611d3c9291602001613d64565b604051602081830303815290604052818581518110611d5d57611d5d6135c7565b60200260200101819052506000730e08d3edef6f0cdf458946a5b0e44ffad1a5cc33631475ff4588604001518b60400151856040518463ffffffff1660e01b8152600401611dad93929190613d93565b600060405180830381865af4158015611dca573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611df291908101906139ee565b600081518110611e0457611e046135c7565b60200260200101519050611e6060006001600160401b03811115611e2a57611e2a612972565b6040519080825280601f01601f191660200182016040528015611e54576020820181803683370190505b50602083015190612698565b611ebb5760405162461bcd60e51b815260206004820152602660248201527f4948616e646c65723a20496e76616c6964206e6f6e2d6d656d6265727368697060448201526510383937b7b360d11b606482015260840161015d565b6040805160208101825285815290516312dde20360e11b81526001600160a01b038c16916325bbc40691611ef29190600401613dc8565b600060405180830381600087803b158015611f0c57600080fd5b505af1158015611f20573d6000803e3d6000fd5b50505050505050508080611f33906136b9565b915050611b82565b505050505050565b81806001600160a01b031663054f7d9c6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015611f84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fa891906134d8565b15611fc55760405162461bcd60e51b815260040161015d90613501565b815151604051631a880a9360e01b81526000916001600160a01b03861691631a880a9391611ff59160040161352b565b6020604051808303816000875af1158015612014573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120389190613542565b846001600160a01b031663b80777ea6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015612078573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061209c9190613542565b6120a69190613571565b9050836001600160a01b031663f3f480d96040518163ffffffff1660e01b81526004016020604051808303816000875af11580156120e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061210c9190613542565b811161212a5760405162461bcd60e51b815260040161015d90613584565b6020830151516000816001600160401b0381111561214a5761214a612972565b60405190808252806020026020018201604052801561219557816020015b60408051606081018252600080825260208083018290529282015282526000199092019101816121685790505b50905060005b8281101561248c576000866020015182815181106121bb576121bb6135c7565b6020026020010151905061223c886001600160a01b031663f437bc596040518163ffffffff1660e01b81526004016000604051808303816000875af1158015612208573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612230919081019061364e565b82516020015190612698565b6122965760405162461bcd60e51b815260206004820152602560248201527f4948616e646c65723a20496e76616c696420726571756573742064657374696e60448201526430ba34b7b760d91b606482015260840161015d565b805160a001516001600160401b031615806123215750876001600160a01b031663b80777ea6040518163ffffffff1660e01b81526004016020604051808303816000875af11580156122ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123109190613542565b815160a001516001600160401b0316115b61236d5760405162461bcd60e51b815260206004820152601b60248201527f4948616e646c65723a20526571756573742074696d6564206f75740000000000604482015260640161015d565b600061237c82600001516126ca565b604051630cb33d1f60e11b8152600481018290529091506001600160a01b038a16906319667a3e906024016020604051808303816000875af11580156123c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123ea91906134d8565b156124375760405162461bcd60e51b815260206004820152601b60248201527f4948616e646c65723a204475706c696361746520726571756573740000000000604482015260640161015d565b604051806060016040528083604001518152602001836020015181526020018281525084848151811061246c5761246c6135c7565b602002602001018190525050508080612484906136b9565b91505061219b565b5084515160405163a70a8c4760e01b81526000916001600160a01b0389169163a70a8c47916124bd9160040161352b565b6060604051808303816000875af11580156124dc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612500919061370c565b602001519050806125235760405162461bcd60e51b815260040161015d90613728565b85516020810151604091820151915163722e206d60e01b815273c7dccd6ca30a7ab7df2e446a0181f16200f093029263722e206d926125689286928891600401613769565b602060405180830381865af4158015612585573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125a991906134d8565b6125f55760405162461bcd60e51b815260206004820181905260248201527f4948616e646c65723a20496e76616c696420726571756573742070726f6f6673604482015260640161015d565b60005b8381101561080f57600087602001518281518110612618576126186135c7565b60200260200101519050886001600160a01b0316633b8c2bf782600001516040518263ffffffff1660e01b81526004016126529190613de3565b600060405180830381600087803b15801561266c57600080fd5b505af1158015612680573d6000803e3d6000fd5b50505050508080612690906136b9565b9150506125f8565b600081518351146126ab575060006126c4565b825160208381018281209186019283209091145b925050505b92915050565b805160208083015160408085015160a08601516060870151608088015160c089015160e08a01519551600099612704999098979101613df6565b604051602081830303815290604052805190602001209050919050565b8051805160208083015160408085015160a086015160c08701516060880151608090980151868a0151945160009961270499989596949593949093909101613e9e565b6040805160208101909152600080825260a083015151909190825b818110156127db57828560a00151828151811061279e5761279e6135c7565b60200260200101516040516020016127b7929190613d64565b604051602081830303815290604052925080806127d3906136b9565b91505061277f565b508360000151846020015185604001518660c0015187608001518860600151878a60e00151604051602001612817989796959493929190613f4c565b6040516020818303038152906040528051906020012092505050919050565b600080826000015160a001516040516020016128529190613fe8565b60408051601f19818403018152828252855180516020828101519483015160c08401516080850151606086015160e0909601519699506000986128a49895979596939592949193928b92909101613f4c565b60408051601f1981840301815291905260208501515190915060005b81811015612949576000866020015182815181106128e0576128e06135c7565b602002602001015190508381600001518260200151604051602001612906929190613d64565b60408051601f19818403018152908290526129249291602001613d64565b6040516020818303038152906040529350508080612941906136b9565b9150506128c0565b505080516020909101209392505050565b6001600160a01b038116811461296f57600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b03811182821017156129aa576129aa612972565b60405290565b604051606081016001600160401b03811182821017156129aa576129aa612972565b60405161010081016001600160401b03811182821017156129aa576129aa612972565b604051601f8201601f191681016001600160401b0381118282101715612a1d57612a1d612972565b604052919050565b600060408284031215612a3757600080fd5b612a3f612988565b9050813581526020820135602082015292915050565b60006001600160401b03821115612a6e57612a6e612972565b5060051b60200190565b600060808284031215612a8a57600080fd5b612a926129b0565b9050612a9e8383612a25565b815260408201356001600160401b03811115612ab957600080fd5b8201601f81018413612aca57600080fd5b80356020612adf612ada83612a55565b6129f5565b82815260059290921b83018101918181019087841115612afe57600080fd5b938201935b83851015612b1c57843582529382019390820190612b03565b808387015250505050506060820135604082015292915050565b60006001600160401b03821115612b4f57612b4f612972565b50601f01601f191660200190565b600082601f830112612b6e57600080fd5b8135612b7c612ada82612b36565b818152846020838601011115612b9157600080fd5b816020850160208301376000918101602001919091529392505050565b80356001600160401b0381168114612bc557600080fd5b919050565b60006101008284031215612bdd57600080fd5b612be56129d2565b905081356001600160401b0380821115612bfe57600080fd5b612c0a85838601612b5d565b83526020840135915080821115612c2057600080fd5b612c2c85838601612b5d565b6020840152612c3d60408501612bae565b60408401526060840135915080821115612c5657600080fd5b612c6285838601612b5d565b60608401526080840135915080821115612c7b57600080fd5b612c8785838601612b5d565b6080840152612c9860a08501612bae565b60a084015260c0840135915080821115612cb157600080fd5b50612cbe84828501612b5d565b60c083015250612cd060e08301612bae565b60e082015292915050565b60008060408385031215612cee57600080fd5b612cf8833561295a565b823591506001600160401b038060208501351115612d1557600080fd5b6020840135840160408187031215612d2c57600080fd5b612d34612988565b8282351115612d4257600080fd5b612d4f8783358401612a78565b81528260208301351115612d6257600080fd5b60208201358201915086601f830112612d7a57600080fd5b612d87612ada8335612a55565b82358082526020808301929160051b850101891015612da557600080fd5b602084015b6020853560051b860101811015612e9b578581351115612dc957600080fd5b601f196060823587018c0382011215612de157600080fd5b612de96129b0565b8760208435890101351115612dfd57600080fd5b823587016020810135016040818e0384011215612e1957600080fd5b612e21612988565b92508860208201351115612e3457600080fd5b612e468d602080840135840101612bca565b83528860408201351115612e5957600080fd5b612e6c8d60206040840135840101612b5d565b602084810191909152928252506040833588018181013583850152606001359082015284529283019201612daa565b506020830152509396939550929350505050565b600082601f830112612ec057600080fd5b81356020612ed0612ada83612a55565b82815260059290921b84018101918181019086841115612eef57600080fd5b8286015b84811015612f2e5780356001600160401b03811115612f125760008081fd5b612f208986838b0101612b5d565b845250918301918301612ef3565b509695505050505050565b600082601f830112612f4a57600080fd5b81356020612f5a612ada83612a55565b82815260059290921b84018101918181019086841115612f7957600080fd5b8286015b84811015612f2e5780356001600160401b0380821115612f9d5760008081fd5b90880190610100828b03601f1901811315612fb85760008081fd5b612fc06129d2565b8784013583811115612fd25760008081fd5b612fe08d8a83880101612b5d565b82525060408085013584811115612ff75760008081fd5b6130058e8b83890101612b5d565b8a840152506060613017818701612bae565b828401526080915081860135858111156130315760008081fd5b61303f8f8c838a0101612b5d565b82850152505060a0613052818701612bae565b8284015260c09150818601358581111561306c5760008081fd5b61307a8f8c838a0101612eaf565b82850152505060e0935061308f848601612bae565b9082015261309e848301612bae565b9281019290925250845250918301918301612f7d565b600080604083850312156130c757600080fd5b82356130d28161295a565b915060208301356001600160401b03808211156130ee57600080fd5b908401906080828703121561310257600080fd5b61310a6129b0565b82358281111561311957600080fd5b61312588828601612eaf565b8252506131358760208501612a25565b602082015260608301358281111561314c57600080fd5b61315888828601612f39565b6040830152508093505050509250929050565b6000806040838503121561317e57600080fd5b82356131898161295a565b915060208301356001600160401b03808211156131a557600080fd5b90840190602082870312156131b957600080fd5b6040516020810181811083821117156131d4576131d4612972565b6040528235828111156131e657600080fd5b6131f288828601612f39565b8252508093505050509250929050565b6000806040838503121561321557600080fd5b82356132208161295a565b915060208301356001600160401b0381111561323b57600080fd5b61324785828601612b5d565b9150509250929050565b6000806040838503121561326457600080fd5b823561326f8161295a565b91506020838101356001600160401b038082111561328c57600080fd5b90850190608082880312156132a057600080fd5b6132a86129b0565b8235828111156132b757600080fd5b8301601f810189136132c857600080fd5b80356132d6612ada82612a55565b81815260059190911b8201860190868101908b8311156132f557600080fd5b8784015b8381101561332d578035878111156133115760008081fd5b61331f8e8b83890101612bca565b8452509188019188016132f9565b508085525050505061334188858501612a25565b84820152606083013593508184111561335957600080fd5b61336588858501612eaf565b6040820152809450505050509250929050565b6000806040838503121561338b57600080fd5b82356133968161295a565b91506020838101356001600160401b03808211156133b357600080fd5b90850190604082880312156133c757600080fd5b6133cf612988565b8235828111156133de57600080fd5b6133ea89828601612a78565b82525083830135828111156133fe57600080fd5b80840193505087601f84011261341357600080fd5b8235613421612ada82612a55565b81815260059190911b8401850190858101908a83111561344057600080fd5b8686015b838110156134c15780358681111561345b57600080fd5b87016060818e03601f190112156134725760008081fd5b61347a6129b0565b898201358881111561348c5760008081fd5b61349a8f8c83860101612bca565b8252506040828101358b830152606090920135918101919091528352918701918701613444565b508087850152505050809450505050509250929050565b6000602082840312156134ea57600080fd5b815180151581146134fa57600080fd5b9392505050565b60208082526010908201526f24a430b7323632b91d10333937bd32b760811b604082015260600190565b8151815260208083015190820152604081016126c4565b60006020828403121561355457600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b818103818111156126c4576126c461355b565b60208082526023908201527f4948616e646c65723a207374696c6c20696e206368616c6c656e6765207065726040820152621a5bd960ea1b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b60005b838110156135f85781810151838201526020016135e0565b50506000910152565b600082601f83011261361257600080fd5b8151613620612ada82612b36565b81815284602083860101111561363557600080fd5b6136468260208301602087016135dd565b949350505050565b60006020828403121561366057600080fd5b81516001600160401b0381111561367657600080fd5b61364684828501613601565b60208082526019908201527f4948616e646c65723a20556e6b6e6f776e207265717565737400000000000000604082015260600190565b6000600182016136cb576136cb61355b565b5060010190565b6000606082840312156136e457600080fd5b6136ec6129b0565b905081518152602082015160208201526040820151604082015292915050565b60006060828403121561371e57600080fd5b6134fa83836136d2565b60208082526021908201527f4948616e646c65723a2050726f6f6620686569676874206e6f7420666f756e646040820152602160f81b606082015260800190565b600060808201868352602060808185015281875180845260a086019150828901935060005b818110156137aa5784518352938301939183019160010161378e565b505060409250848103838601528087518083528383019150838901925060005b818110156137f957835180518452858101518685015286015186840152928401926060909201916001016137ca565b50508094505050505082606083015295945050505050565b600081518084526138298160208601602086016135dd565b601f01601f19169290920160200192915050565b6000610100825181855261385382860182613811565b9150506020830151848203602086015261386d8282613811565b915050604083015161388a60408601826001600160401b03169052565b50606083015184820360608601526138a28282613811565b915050608083015184820360808601526138bc8282613811565b91505060a08301516138d960a08601826001600160401b03169052565b5060c083015184820360c08601526138f18282613811565b91505060e083015161390e60e08601826001600160401b03169052565b509392505050565b602081526000825160406020840152613932606084018261383d565b90506020840151601f198483030160408501526126bf8282613811565b600081518084526020808501808196508360051b8101915082860160005b85811015613997578284038952613985848351613811565b9885019893509084019060010161396d565b5091979650505050505050565b8481526080602082015260006139bd608083018661394f565b82810360408401526139cf818661394f565b905082810360608401526139e38185613811565b979650505050505050565b60006020808385031215613a0157600080fd5b82516001600160401b0380821115613a1857600080fd5b818501915085601f830112613a2c57600080fd5b8151613a3a612ada82612a55565b81815260059190911b83018401908481019088831115613a5957600080fd5b8585015b83811015613aec57805185811115613a755760008081fd5b86016040818c03601f1901811315613a8d5760008081fd5b613a95612988565b8983015188811115613aa75760008081fd5b613ab58e8c83870101613601565b825250908201519087821115613acb5760008081fd5b613ad98d8b84860101613601565b818b015285525050918601918601613a5d565b5098975050505050505050565b60006101008251818552613b0f82860182613811565b91505060208301518482036020860152613b298282613811565b9150506040830151613b4660408601826001600160401b03169052565b5060608301518482036060860152613b5e8282613811565b9150506080830151613b7b60808601826001600160401b03169052565b5060a083015184820360a0860152613b93828261394f565b91505060c0830151613bb060c08601826001600160401b03169052565b5060e083015161390e60e08601826001600160401b03169052565b60006020808352835160408083860152613be86060860183613af9565b83870151601f1987830381018489015281518084529294509085019184860190600581901b8601870160005b82811015613c62578488830301845285518051888452613c3689850182613811565b918b0151848303858d0152919050613c4e8183613811565b978b0197958b019593505050600101613c14565b509a9950505050505050505050565b6020815260006134fa6020830184613af9565b600060208284031215613c9657600080fd5b81516134fa8161295a565b604081526000613cb46040830185613811565b8281036020840152613cc68185613811565b95945050505050565b60008082840360c0811215613ce357600080fd5b83516001600160401b03811115613cf957600080fd5b613d0586828701613601565b93505060a0601f1982011215613d1a57600080fd5b50613d236129b0565b6020840151815260408401516020820152613d4185606086016136d2565b6040820152809150509250929050565b6020815260006134fa6020830184613811565b60008351613d768184602088016135dd565b835190830190613d8a8183602088016135dd565b01949350505050565b838152606060208201526000613dac606083018561394f565b8281036040840152613dbe818561394f565b9695505050505050565b6020815260008251602080840152613646604084018261383d565b6020815260006134fa602083018461383d565b60008951613e08818460208e016135dd565b895190830190613e1c818360208e016135dd565b60c08a811b6001600160c01b03199081169390920192835289901b811660088301528751613e51816010850160208c016135dd565b8751920191613e67816010850160208b016135dd565b8651920191613e7d816010850160208a016135dd565b60c09590951b16930160108101939093525050601801979650505050505050565b600089516020613eb18285838f016135dd565b8a5191840191613ec48184848f016135dd565b60c08b811b6001600160c01b0319908116949092019384528a901b1660088301528751613ef78160108501848c016135dd565b8751920191613f0c8160108501848b016135dd565b8651920191613f218160108501848a016135dd565b8551920191613f3681601085018489016135dd565b919091016010019b9a5050505050505050505050565b60008951613f5e818460208e016135dd565b895190830190613f72818360208e016135dd565b60c08a811b6001600160c01b03199081169390920192835289811b8216600884015288901b811660108301528651613fb1816018850160208b016135dd565b8651920191613fc7816018850160208a016135dd565b60c09590951b16930160188101939093525050602001979650505050505050565b6020815260006134fa602083018461394f56fea2646970667358221220f7655f63159e9b3a74f2aa456aba017ca61fbf2ebcdad44e0257eef9a5e4da3c64736f6c63430008110033
Loading...
Loading
Loading...
Loading
Loading...
Loading
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.