Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
Latest 25 from a total of 2,946 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
Amount
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Handle Post Requ... | 16060551 | 446 days ago | IN | 0 ETH | 0.000000059586 | ||||
| Handle Post Requ... | 15974143 | 448 days ago | IN | 0 ETH | 0.000000206311 | ||||
| Handle Post Requ... | 15974139 | 448 days ago | IN | 0 ETH | 0.000000212072 | ||||
| Handle Post Requ... | 15930935 | 449 days ago | IN | 0 ETH | 0.000002480014 | ||||
| Handle Post Requ... | 15930931 | 449 days ago | IN | 0 ETH | 0.000002211673 | ||||
| Handle Post Requ... | 15930927 | 449 days ago | IN | 0 ETH | 0.000002211673 | ||||
| Handle Post Requ... | 15930923 | 449 days ago | IN | 0 ETH | 0.000002268462 | ||||
| Handle Post Requ... | 15887718 | 450 days ago | IN | 0 ETH | 0.000000322284 | ||||
| Handle Post Requ... | 15887714 | 450 days ago | IN | 0 ETH | 0.000000322284 | ||||
| Handle Post Requ... | 15887710 | 450 days ago | IN | 0 ETH | 0.00000031298 | ||||
| Handle Post Requ... | 15887706 | 450 days ago | IN | 0 ETH | 0.00000031298 | ||||
| Handle Post Requ... | 15887702 | 450 days ago | IN | 0 ETH | 0.000000323475 | ||||
| Handle Post Requ... | 15498086 | 459 days ago | IN | 0 ETH | 0.000000715317 | ||||
| Handle Post Requ... | 15498082 | 459 days ago | IN | 0 ETH | 0.000000739822 | ||||
| Handle Post Requ... | 15498078 | 459 days ago | IN | 0 ETH | 0.000000756808 | ||||
| Handle Post Requ... | 15498074 | 459 days ago | IN | 0 ETH | 0.000000756808 | ||||
| Handle Post Requ... | 15498070 | 459 days ago | IN | 0 ETH | 0.000000689813 | ||||
| Handle Post Requ... | 15454729 | 460 days ago | IN | 0 ETH | 0.000001066894 | ||||
| Handle Post Requ... | 15454725 | 460 days ago | IN | 0 ETH | 0.000001045672 | ||||
| Handle Post Requ... | 15454721 | 460 days ago | IN | 0 ETH | 0.00000107689 | ||||
| Handle Post Requ... | 15454717 | 460 days ago | IN | 0 ETH | 0.00000107689 | ||||
| Handle Post Requ... | 15454713 | 460 days ago | IN | 0 ETH | 0.000001162993 | ||||
| Handle Post Requ... | 15324197 | 463 days ago | IN | 0 ETH | 0.000001720018 | ||||
| Handle Post Requ... | 15324193 | 463 days ago | IN | 0 ETH | 0.000001720018 | ||||
| Handle Post Requ... | 15324189 | 463 days ago | IN | 0 ETH | 0.000001569846 |
Latest 1 internal transaction
| Parent Transaction Hash | Block | From | To | Amount | ||
|---|---|---|---|---|---|---|
| 12199718 | 536 days ago | Contract Creation | 0 ETH |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
HandlerV1
Compiler Version
v0.8.17+commit.8df45f5f
Optimization Enabled:
Yes with 200 runs
Other Settings:
london EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// Copyright (C) Polytope Labs Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
pragma solidity 0.8.17;
import {MerkleMountainRange, MmrLeaf} from "solidity-merkle-trees/MerkleMountainRange.sol";
import {MerklePatricia, StorageValue} from "solidity-merkle-trees/MerklePatricia.sol";
import {Context} from "openzeppelin/utils/Context.sol";
import {Bytes} from "solidity-merkle-trees/trie/Bytes.sol";
import {IConsensusClient, IntermediateState, StateMachineHeight, StateCommitment} from "ismp/IConsensusClient.sol";
import {IHandler} from "ismp/IHandler.sol";
import {IIsmpHost, PostResponse, PostRequest, GetRequest, GetResponse, FeeMetadata} from "ismp/IIsmpHost.sol";
import {
Message,
PostRequestMessage,
PostResponseMessage,
GetResponseMessage,
PostRequestTimeoutMessage,
PostResponseTimeoutMessage,
GetTimeoutMessage,
PostRequestLeaf,
PostResponseLeaf
} from "ismp/Message.sol";
// Storage prefix for request receipts in the pallet-ismp child trie
bytes constant REQUEST_RECEIPTS_STORAGE_PREFIX = hex"526571756573745265636569707473";
// Storage prefix for request receipts in the pallet-ismp child trie
bytes constant RESPONSE_RECEIPTS_STORAGE_PREFIX = hex"526573706f6e73655265636569707473";
/// Entry point for the hyperbridge. Implementation of the ISMP handler protocol
contract HandlerV1 is IHandler, Context {
using Bytes for bytes;
using Message for PostResponse;
using Message for PostRequest;
using Message for GetRequest;
// using Message for GetResponse;
modifier notFrozen(IIsmpHost host) {
require(!host.frozen(), "IHandler: frozen");
_;
}
/**
* @dev Handle incoming consensus messages. These message are accompanied with some cryptographic proof.
* If the Host's internal consensus client verifies this proof successfully,
* The `StateCommitment` enters the preconfigured challenge period.
* @param host - `IsmpHost`
* @param proof - consensus proof
*/
function handleConsensus(IIsmpHost host, bytes calldata proof) external notFrozen(host) {
uint256 delay = block.timestamp - host.consensusUpdateTime();
require(delay < host.unStakingPeriod(), "IHandler: consensus client is now expired");
(bytes memory verifiedState, IntermediateState memory intermediate) =
IConsensusClient(host.consensusClient()).verifyConsensus(host.consensusState(), proof);
host.storeConsensusState(verifiedState);
// check that we know this state machine and it's a new update
uint256 latestHeight = host.latestStateMachineHeight(intermediate.stateMachineId);
if (latestHeight != 0 && intermediate.height > latestHeight) {
StateMachineHeight memory stateMachineHeight =
StateMachineHeight({stateMachineId: intermediate.stateMachineId, height: intermediate.height});
host.storeStateMachineCommitment(stateMachineHeight, intermediate.commitment);
}
}
/**
* @dev Checks the provided requests and their proofs, before dispatching them to their relevant destination modules
* @param host - `IsmpHost`
* @param request - batch post requests
*/
function handlePostRequests(IIsmpHost host, PostRequestMessage calldata request) external notFrozen(host) {
uint256 timestamp = block.timestamp;
uint256 delay = timestamp - host.stateMachineCommitmentUpdateTime(request.proof.height);
uint256 challengePeriod = host.challengePeriod();
require(challengePeriod == 0 || delay > 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];
// check destination
require(leaf.request.dest.equals(host.host()), "IHandler: Invalid request destination");
// check time-out
require(leaf.request.timeout() > timestamp, "IHandler: Request timed out");
// duplicate request?
bytes32 commitment = leaf.request.hash();
require(host.requestReceipts(commitment) == address(0), "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, _msgSender());
}
}
/**
* @dev Checks the provided responses and their proofs, before dispatching them to their relevant destination modules
* @param host - `IsmpHost`
* @param response - batch post responses
*/
function handlePostResponses(IIsmpHost host, PostResponseMessage calldata response) external notFrozen(host) {
uint256 timestamp = block.timestamp;
uint256 delay = timestamp - host.stateMachineCommitmentUpdateTime(response.proof.height);
uint256 challengePeriod = host.challengePeriod();
require(challengePeriod == 0 || delay > 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];
// check time-out
require(leaf.response.timeout() > timestamp, "IHandler: Response timed out");
// known request? also serves as a source check
bytes32 requestCommitment = leaf.response.request.hash();
FeeMetadata memory meta = host.requestCommitments(requestCommitment);
require(meta.sender != address(0), "IHandler: Unknown request");
// duplicate response?
require(host.responseReceipts(requestCommitment).relayer == address(0), "IHandler: Duplicate Post response");
leaves[i] = MmrLeaf(leaf.kIndex, leaf.index, leaf.response.hash());
}
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, _msgSender());
}
}
/**
* @dev Checks the provided timed-out requests and their proofs, before dispatching them to their relevant destination modules
* @param host - IsmpHost
* @param message - batch post request timeouts
*/
function handlePostRequestTimeouts(IIsmpHost host, PostRequestTimeoutMessage calldata message)
external
notFrozen(host)
{
uint256 delay = block.timestamp - host.stateMachineCommitmentUpdateTime(message.height);
uint256 challengePeriod = host.challengePeriod();
require(challengePeriod == 0 || delay > challengePeriod, "IHandler: still in challenge period");
// fetch the state commitment
StateCommitment memory state = host.stateMachineCommitment(message.height);
require(state.stateRoot != bytes32(0), "IHandler: State Commitment doesn't exist");
uint256 timeoutsLength = message.timeouts.length;
for (uint256 i = 0; i < timeoutsLength; i++) {
PostRequest memory request = message.timeouts[i];
// timed-out?
require(state.timestamp > request.timeout(), "Request not timed out");
// known request? also serves as source check
bytes32 requestCommitment = request.hash();
FeeMetadata memory meta = host.requestCommitments(requestCommitment);
require(meta.sender != address(0), "IHandler: Unknown request");
bytes[] memory keys = new bytes[](1);
keys[i] = bytes.concat(REQUEST_RECEIPTS_STORAGE_PREFIX, bytes.concat(requestCommitment));
// verify state trie non-membership proofs
StorageValue memory entry = MerklePatricia.VerifySubstrateProof(state.stateRoot, message.proof, keys)[0];
require(entry.value.equals(new bytes(0)), "IHandler: Invalid non-membership proof");
host.dispatchIncoming(request, meta, requestCommitment);
}
}
/**
* @dev Check the provided timeouts and their proofs before dispatching them to their relevant modules
* @param host - Ismp host
* @param message - batch post response timeouts
*/
function handlePostResponseTimeouts(IIsmpHost host, PostResponseTimeoutMessage calldata message)
external
notFrozen(host)
{
uint256 delay = block.timestamp - host.stateMachineCommitmentUpdateTime(message.height);
uint256 challengePeriod = host.challengePeriod();
require(challengePeriod == 0 || delay > challengePeriod, "IHandler: still in challenge period");
// fetch the state commitment
StateCommitment memory state = host.stateMachineCommitment(message.height);
require(state.stateRoot != bytes32(0), "IHandler: State Commitment doesn't exist");
uint256 timeoutsLength = message.timeouts.length;
for (uint256 i = 0; i < timeoutsLength; i++) {
PostResponse memory response = message.timeouts[i];
// timed-out?
require(state.timestamp > response.timeout(), "IHandler: Response not timed out");
// known response? also serves as source check
bytes32 responseCommitment = response.hash();
FeeMetadata memory meta = host.responseCommitments(responseCommitment);
require(meta.sender != address(0), "IHandler: Unknown response");
bytes[] memory keys = new bytes[](1);
keys[i] = bytes.concat(RESPONSE_RECEIPTS_STORAGE_PREFIX, bytes.concat(responseCommitment));
// verify state trie non-membership proofs
StorageValue memory entry = MerklePatricia.VerifySubstrateProof(state.stateRoot, message.proof, keys)[0];
require(entry.value.equals(new bytes(0)), "IHandler: Invalid non-membership proof");
host.dispatchIncoming(response, meta, responseCommitment);
}
}
/**
* @dev check response proofs, message delay and timeouts, then dispatch get responses to modules
* @param host - Ismp host
* @param message - batch get responses
*/
function handleGetResponses(IIsmpHost host, GetResponseMessage calldata message) external notFrozen(host) {
uint256 timestamp = block.timestamp;
uint256 delay = timestamp - host.stateMachineCommitmentUpdateTime(message.height);
uint256 challengePeriod = host.challengePeriod();
require(challengePeriod == 0 || delay > challengePeriod, "IHandler: still in challenge period");
bytes32 root = host.stateMachineCommitment(message.height).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];
// timed-out?
require(request.timeout() > timestamp, "IHandler: GET request timed out");
// known request? also serves as source check
bytes32 requestCommitment = request.hash();
FeeMetadata memory meta = host.requestCommitments(requestCommitment);
require(meta.sender != address(0), "IHandler: Unknown GET request");
// duplicate response?
require(host.responseReceipts(requestCommitment).relayer == address(0), "IHandler: Duplicate GET response");
StorageValue[] memory values =
MerklePatricia.ReadChildProofCheck(root, proof, request.keys, bytes.concat(requestCommitment));
GetResponse memory response = GetResponse({request: request, values: values});
host.dispatchIncoming(response, _msgSender());
}
}
/**
* @dev Check the provided Get request timeouts, then dispatch to modules
* @param host - Ismp host
* @param message - batch get request timeouts
*/
function handleGetRequestTimeouts(IIsmpHost host, GetTimeoutMessage calldata message) external notFrozen(host) {
uint256 timeoutsLength = message.timeouts.length;
uint256 timestamp = block.timestamp;
for (uint256 i = 0; i < timeoutsLength; i++) {
GetRequest memory request = message.timeouts[i];
bytes32 requestCommitment = request.hash();
FeeMetadata memory meta = host.requestCommitments(requestCommitment);
require(meta.sender != address(0), "IHandler: Unknown request");
require(timestamp > request.timeout(), "IHandler: GET request not timed out");
host.dispatchIncoming(request, meta, requestCommitment);
}
}
}// 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 provided root node
function VerifyProof(bytes32 root, bytes32[] memory proof, MmrLeaf[] memory leaves, uint256 mmrSize)
internal
pure
returns (bool)
{
return root == CalculateRoot(proof, leaves, mmrSize);
}
/// @notice Calculate merkle root
/// @notice this method allows computing the root hash of a merkle tree using Merkle Mountain Range
/// @param proof A list of the merkle nodes that are needed to re-calculate root node.
/// @param leaves a list of mmr leaves to prove
/// @param leafCount the size of the merkle tree
/// @return bytes32 hash of the computed root node
function CalculateRoot(bytes32[] memory proof, MmrLeaf[] memory leaves, uint256 leafCount)
internal
pure
returns (bytes32)
{
// special handle the only 1 leaf MMR
if (leafCount == 1 && leaves.length == 1 && leaves[0].leaf_index == 0) {
return leaves[0].hash;
}
uint256[] memory subtrees = subtreeHeights(leafCount);
uint256 length = subtrees.length;
Iterator memory peakRoots = Iterator(0, new bytes32[](length));
Iterator memory proofIter = Iterator(0, proof);
uint256 current_subtree;
for (uint256 p; p < length;) {
uint256 height = subtrees[p];
current_subtree += 2 ** height;
MmrLeaf[] memory subtreeLeaves = new MmrLeaf[](0);
if (leaves.length > 0) {
(subtreeLeaves, leaves) = leavesForSubtree(leaves, current_subtree);
}
if (subtreeLeaves.length == 0) {
if (proofIter.data.length == proofIter.offset) {
break;
} else {
push(peakRoots, next(proofIter));
}
} else if (subtreeLeaves.length == 1 && height == 0) {
push(peakRoots, subtreeLeaves[0].hash);
} else {
push(peakRoots, CalculateSubtreeRoot(subtreeLeaves, proofIter, height));
}
unchecked {
++p;
}
}
unchecked {
peakRoots.offset--;
}
while (peakRoots.offset != 0) {
bytes32 right = previous(peakRoots);
bytes32 left = previous(peakRoots);
unchecked {
++peakRoots.offset;
}
peakRoots.data[peakRoots.offset] = keccak256(abi.encodePacked(right, left));
}
return peakRoots.data[0];
}
function subtreeHeights(uint256 leavesLength) internal pure returns (uint256[] memory) {
uint256 maxSubtrees = 64;
uint256[] memory indices = new uint256[](maxSubtrees);
uint256 i;
uint256 current = leavesLength;
for (; i < maxSubtrees;) {
if (current == 0) {
break;
}
uint256 log = Math.log2(current);
indices[i] = log;
current = current - 2 ** log;
unchecked {
++i;
}
}
// resize array?, sigh solidity.
uint256 excess = maxSubtrees - i;
assembly {
mstore(indices, sub(mload(indices), excess))
}
return indices;
}
/// @notice calculate root hash of a subtree of the merkle mountain
/// @param peakLeaves a list of nodes to provide proof for
/// @param proofIter a list of node hashes to traverse to compute the peak root hash
/// @param height Height of the subtree
/// @return peakRoot a tuple containing the peak root hash, and the peak root position in the merkle
function CalculateSubtreeRoot(MmrLeaf[] memory peakLeaves, Iterator memory proofIter, uint256 height)
internal
pure
returns (bytes32)
{
uint256[] memory current_layer;
Node[] memory leaves;
(leaves, current_layer) = mmrLeafToNode(peakLeaves);
Node[][] memory layers = new Node[][](height);
for (uint256 i; i < height;) {
uint256 nodelength = 2 ** (height - i);
if (current_layer.length == nodelength) {
break;
}
uint256[] memory siblings = siblingIndices(current_layer);
uint256[] memory diff = difference(siblings, current_layer);
uint256 length = diff.length;
layers[i] = new Node[](length);
for (uint256 j; j < length;) {
layers[i][j] = Node(diff[j], next(proofIter));
unchecked {
++j;
}
}
current_layer = parentIndices(siblings);
unchecked {
++i;
}
}
return MerkleMultiProof.CalculateRoot(layers, leaves);
}
/**
* @notice difference ensures all nodes have a sibling.
* @dev left and right are designed to be equal length array
* @param left a list of hashes
* @param right a list of hashes to compare
* @return uint256[] a new array with difference
*/
function difference(uint256[] memory left, uint256[] memory right) internal pure returns (uint256[] memory) {
uint256 length = left.length;
uint256 rightLength = right.length;
uint256[] memory diff = new uint256[](length);
uint256 d;
for (uint256 i; i < length;) {
bool found;
for (uint256 j; j < rightLength;) {
if (left[i] == right[j]) {
found = true;
break;
}
unchecked {
++j;
}
}
if (!found) {
diff[d] = left[i];
d++;
}
unchecked {
++i;
}
}
// resize array?, sigh solidity.
uint256 excess = length - d;
assembly {
mstore(diff, sub(mload(diff), excess))
}
return diff;
}
/**
* @dev calculates the index of each sibling index of the proof nodes
* @dev proof nodes are the nodes that will be traversed to estimate the root hash
* @param indices a list of proof nodes indices
* @return uint256[] a list of sibling indices
*/
function siblingIndices(uint256[] memory indices) internal pure returns (uint256[] memory) {
uint256 length = indices.length;
uint256[] memory siblings = new uint256[](length);
for (uint256 i; i < length;) {
uint256 index = indices[i];
if (index == 0) {
siblings[i] = index + 1;
} else if (index % 2 == 0) {
siblings[i] = index + 1;
} else {
siblings[i] = index - 1;
}
unchecked {
++i;
}
}
return siblings;
}
/**
* @notice Compute Parent Indices
* @dev Used internally to calculate the indices of the parent nodes of the provided proof nodes
* @param indices a list of indices of proof nodes in a merkle mountain
* @return uint256[] a list of parent indices for each index provided
*/
function parentIndices(uint256[] memory indices) internal pure returns (uint256[] memory) {
uint256 length = indices.length;
uint256[] memory parents = new uint256[](length);
uint256 k;
for (uint256 i; i < length; i++) {
uint256 index = indices[i] / 2;
if (k > 0 && parents[k - 1] == index) {
continue;
}
parents[k] = index;
unchecked {
++k;
}
}
// resize array?, sigh solidity.
uint256 excess = length - k;
assembly {
mstore(parents, sub(mload(parents), excess))
}
return parents;
}
/**
* @notice Convert Merkle mountain Leaf to a Merkle Node
* @param leaves list of merkle mountain range leaf
* @return A tuple with the list of merkle nodes and the list of nodes at 0 and 1 respectively
*/
function mmrLeafToNode(MmrLeaf[] memory leaves) internal pure returns (Node[] memory, uint256[] memory) {
uint256 i;
uint256 length = leaves.length;
Node[] memory nodes = new Node[](length);
uint256[] memory indices = new uint256[](length);
while (i < length) {
nodes[i] = Node(leaves[i].k_index, leaves[i].hash);
indices[i] = leaves[i].k_index;
++i;
}
return (nodes, indices);
}
/**
* @notice Get a mountain peak's leaves
* @notice this splits the leaves into either side of the peak [left & right]
* @param leaves a list of mountain merkle leaves, for a subtree
* @param leafIndex the index of the leaf of the next subtree
* @return A tuple of 2 arrays of mountain merkle leaves. Index 1 and 2 represent left and right of the peak respectively
*/
function leavesForSubtree(MmrLeaf[] memory leaves, uint256 leafIndex)
internal
pure
returns (MmrLeaf[] memory, MmrLeaf[] memory)
{
uint256 p;
uint256 length = leaves.length;
for (; p < length; p++) {
if (leafIndex <= leaves[p].leaf_index) {
break;
}
}
uint256 len = p == 0 ? 0 : p;
MmrLeaf[] memory left = new MmrLeaf[](len);
MmrLeaf[] memory right = new MmrLeaf[](length - len);
uint256 i;
uint256 leftLength = left.length;
while (i < leftLength) {
left[i] = leaves[i];
++i;
}
uint256 j;
while (i < length) {
right[j] = leaves[i];
++i;
++j;
}
return (left, right);
}
function push(Iterator memory iterator, bytes32 data) internal pure {
iterator.data[iterator.offset] = data;
unchecked {
++iterator.offset;
}
}
function next(Iterator memory iterator) internal pure returns (bytes32) {
bytes32 data = iterator.data[iterator.offset];
unchecked {
++iterator.offset;
}
return data;
}
function previous(Iterator memory iterator) internal pure returns (bytes32) {
bytes32 data = iterator.data[iterator.offset];
unchecked {
--iterator.offset;
}
return data;
}
}pragma solidity 0.8.17;
import "./trie/Node.sol";
import "./trie/Option.sol";
import "./trie/NibbleSlice.sol";
import "./trie/TrieDB.sol";
import "./trie/substrate/SubstrateTrieDB.sol";
import "./trie/ethereum/EthereumTrieDB.sol";
// 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 Verifies substrate specific merkle patricia proofs.
* @param root hash of the merkle patricia trie
* @param proof a list of proof nodes
* @param keys a list of keys to verify
* @return bytes[] a list of values corresponding to the supplied keys.
*/
function VerifySubstrateProof(bytes32 root, bytes[] memory proof, bytes[] memory keys)
public
pure
returns (StorageValue[] memory)
{
StorageValue[] memory values = new StorageValue[](keys.length);
TrieNode[] memory nodes = new TrieNode[](proof.length);
for (uint256 i = 0; i < proof.length; i++) {
nodes[i] = TrieNode(keccak256(proof[i]), proof[i]);
}
for (uint256 i = 0; i < keys.length; i++) {
values[i].key = keys[i];
NibbleSlice memory keyNibbles = NibbleSlice(keys[i], 0);
NodeKind memory node = SubstrateTrieDB.decodeNodeKind(TrieDB.get(nodes, root));
// This loop is unbounded so that an adversary cannot insert a deeply nested key in the trie
// and successfully convince us of it's non-existence, if we consume the block gas limit while
// traversing the trie, then the transaction should revert.
for (uint256 j = 1; j > 0; j++) {
NodeHandle memory nextNode;
if (TrieDB.isLeaf(node)) {
Leaf memory leaf = SubstrateTrieDB.decodeLeaf(node);
if (NibbleSliceOps.eq(leaf.key, keyNibbles)) {
values[i].value = TrieDB.load(nodes, leaf.value);
}
break;
} else if (TrieDB.isNibbledBranch(node)) {
NibbledBranch memory nibbled = SubstrateTrieDB.decodeNibbledBranch(node);
uint256 nibbledBranchKeyLength = NibbleSliceOps.len(nibbled.key);
if (!NibbleSliceOps.startsWith(keyNibbles, nibbled.key)) {
break;
}
if (NibbleSliceOps.len(keyNibbles) == nibbledBranchKeyLength) {
if (Option.isSome(nibbled.value)) {
values[i].value = TrieDB.load(nodes, nibbled.value.value);
}
break;
} else {
uint256 index = NibbleSliceOps.at(keyNibbles, nibbledBranchKeyLength);
NodeHandleOption memory handle = nibbled.children[index];
if (Option.isSome(handle)) {
keyNibbles = NibbleSliceOps.mid(keyNibbles, nibbledBranchKeyLength + 1);
nextNode = handle.value;
} else {
break;
}
}
} else if (TrieDB.isEmpty(node)) {
break;
}
node = SubstrateTrieDB.decodeNodeKind(TrieDB.load(nodes, nextNode));
}
}
return values;
}
/**
* @notice Verify child trie keys
* @dev substrate specific method in order to verify keys in the child trie.
* @param root hash of the merkle root
* @param proof a list of proof nodes
* @param keys a list of keys to verify
* @param childInfo data that can be used to compute the root of the child trie
* @return bytes[], a list of values corresponding to the supplied keys.
*/
function ReadChildProofCheck(bytes32 root, bytes[] memory proof, bytes[] memory keys, bytes memory childInfo)
public
pure
returns (StorageValue[] memory)
{
// fetch the child trie root hash;
bytes memory prefix = bytes(":child_storage:default:");
bytes memory key = bytes.concat(prefix, childInfo);
bytes[] memory _keys = new bytes[](1);
_keys[0] = key;
StorageValue[] memory values = VerifySubstrateProof(root, proof, _keys);
bytes32 childRoot = bytes32(values[0].value);
require(childRoot != bytes32(0), "Invalid child trie proof");
return VerifySubstrateProof(childRoot, proof, keys);
}
/**
* @notice Verifies ethereum specific merkle patricia proofs as described by EIP-1188.
* @param root hash of the merkle patricia trie
* @param proof a list of proof nodes
* @param keys a list of keys to verify
* @return bytes[] a list of values corresponding to the supplied keys.
*/
function VerifyEthereumProof(bytes32 root, bytes[] memory proof, bytes[] memory keys)
public
pure
returns (StorageValue[] memory)
{
StorageValue[] memory values = new StorageValue[](keys.length);
TrieNode[] memory nodes = new TrieNode[](proof.length);
for (uint256 i = 0; i < proof.length; i++) {
nodes[i] = TrieNode(keccak256(proof[i]), proof[i]);
}
for (uint256 i = 0; i < keys.length; i++) {
values[i].key = keys[i];
NibbleSlice memory keyNibbles = NibbleSlice(keys[i], 0);
NodeKind memory node = EthereumTrieDB.decodeNodeKind(TrieDB.get(nodes, root));
// This loop is unbounded so that an adversary cannot insert a deeply nested key in the trie
// and successfully convince us of it's non-existence, if we consume the block gas limit while
// traversing the trie, then the transaction should revert.
for (uint256 j = 1; j > 0; j++) {
NodeHandle memory nextNode;
if (TrieDB.isLeaf(node)) {
Leaf memory leaf = EthereumTrieDB.decodeLeaf(node);
// Let's retrieve the offset to be used
uint256 offset = keyNibbles.offset % 2 == 0 ? keyNibbles.offset / 2 : keyNibbles.offset / 2 + 1;
// Let's cut the key passed as input
keyNibbles = NibbleSlice(NibbleSliceOps.bytesSlice(keyNibbles.data, offset), 0);
if (NibbleSliceOps.eq(leaf.key, keyNibbles)) {
values[i].value = TrieDB.load(nodes, leaf.value);
}
break;
} else if (TrieDB.isExtension(node)) {
Extension memory extension = EthereumTrieDB.decodeExtension(node);
if (NibbleSliceOps.startsWith(keyNibbles, extension.key)) {
// Let's cut the key passed as input
uint256 cutNibble = keyNibbles.offset + NibbleSliceOps.len(extension.key);
keyNibbles = NibbleSlice(
NibbleSliceOps.bytesSlice(keyNibbles.data, cutNibble / 2), cutNibble % 2
);
nextNode = extension.node;
} else {
break;
}
} else if (TrieDB.isBranch(node)) {
Branch memory branch = EthereumTrieDB.decodeBranch(node);
if (NibbleSliceOps.isEmpty(keyNibbles)) {
if (Option.isSome(branch.value)) {
values[i].value = TrieDB.load(nodes, branch.value.value);
}
break;
} else {
NodeHandleOption memory handle = branch.children[NibbleSliceOps.at(keyNibbles, 0)];
if (Option.isSome(handle)) {
keyNibbles = NibbleSliceOps.mid(keyNibbles, 1);
nextNode = handle.value;
} else {
break;
}
}
} else if (TrieDB.isEmpty(node)) {
break;
}
node = EthereumTrieDB.decodeNodeKind(TrieDB.load(nodes, nextNode));
}
}
return values;
}
}// 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;
}
}pragma solidity 0.8.17;
// SPDX-License-Identifier: Apache2
import {Memory} from "./Memory.sol";
struct ByteSlice {
bytes data;
uint256 offset;
}
library Bytes {
uint256 internal constant BYTES_HEADER_SIZE = 32;
// Checks if two `bytes memory` variables are equal. This is done using hashing,
// which is much more gas efficient then comparing each byte individually.
// Equality means that:
// - 'self.length == other.length'
// - For 'n' in '[0, self.length)', 'self[n] == other[n]'
function equals(bytes memory self, bytes memory other) internal pure returns (bool equal) {
if (self.length != other.length) {
return false;
}
uint256 addr;
uint256 addr2;
assembly {
addr := add(self, /*BYTES_HEADER_SIZE*/ 32)
addr2 := add(other, /*BYTES_HEADER_SIZE*/ 32)
}
equal = Memory.equals(addr, addr2, self.length);
}
function readByte(ByteSlice memory self) internal pure returns (uint8) {
if (self.offset + 1 > self.data.length) {
revert("Out of range");
}
uint8 b = uint8(self.data[self.offset]);
self.offset += 1;
return b;
}
// Copies 'len' bytes from 'self' into a new array, starting at the provided 'startIndex'.
// Returns the new copy.
// Requires that:
// - 'startIndex + len <= self.length'
// The length of the substring is: 'len'
function read(ByteSlice memory self, uint256 len) internal pure returns (bytes memory) {
require(self.offset + len <= self.data.length);
if (len == 0) {
return "";
}
uint256 addr = Memory.dataPtr(self.data);
bytes memory slice = Memory.toBytes(addr + self.offset, len);
self.offset += len;
return slice;
}
// Copies a section of 'self' into a new array, starting at the provided 'startIndex'.
// Returns the new copy.
// Requires that 'startIndex <= self.length'
// The length of the substring is: 'self.length - startIndex'
function substr(bytes memory self, uint256 startIndex) internal pure returns (bytes memory) {
require(startIndex <= self.length);
uint256 len = self.length - startIndex;
uint256 addr = Memory.dataPtr(self);
return Memory.toBytes(addr + startIndex, len);
}
// Copies 'len' bytes from 'self' into a new array, starting at the provided 'startIndex'.
// Returns the new copy.
// Requires that:
// - 'startIndex + len <= self.length'
// The length of the substring is: 'len'
function substr(bytes memory self, uint256 startIndex, uint256 len) internal pure returns (bytes memory) {
require(startIndex + len <= self.length);
if (len == 0) {
return "";
}
uint256 addr = Memory.dataPtr(self);
return Memory.toBytes(addr + startIndex, len);
}
// Combines 'self' and 'other' into a single array.
// Returns the concatenated arrays:
// [self[0], self[1], ... , self[self.length - 1], other[0], other[1], ... , other[other.length - 1]]
// The length of the new array is 'self.length + other.length'
function concat(bytes memory self, bytes memory other) internal pure returns (bytes memory) {
bytes memory ret = new bytes(self.length + other.length);
uint256 src;
uint256 srcLen;
(src, srcLen) = Memory.fromBytes(self);
uint256 src2;
uint256 src2Len;
(src2, src2Len) = Memory.fromBytes(other);
uint256 dest;
(dest,) = Memory.fromBytes(ret);
uint256 dest2 = dest + srcLen;
Memory.copy(src, dest, srcLen);
Memory.copy(src2, dest2, src2Len);
return ret;
}
function toBytes32(bytes memory self) internal pure returns (bytes32 out) {
require(self.length >= 32, "Bytes:: toBytes32: data is to short.");
assembly {
out := mload(add(self, 32))
}
}
function toBytes16(bytes memory self, uint256 offset) internal pure returns (bytes16 out) {
for (uint256 i = 0; i < 16; i++) {
out |= bytes16(bytes1(self[offset + i]) & 0xFF) >> (i * 8);
}
}
function toBytes8(bytes memory self, uint256 offset) internal pure returns (bytes8 out) {
for (uint256 i = 0; i < 8; i++) {
out |= bytes8(bytes1(self[offset + i]) & 0xFF) >> (i * 8);
}
}
function toBytes4(bytes memory self, uint256 offset) internal pure returns (bytes4) {
bytes4 out;
for (uint256 i = 0; i < 4; i++) {
out |= bytes4(self[offset + i] & 0xFF) >> (i * 8);
}
return out;
}
function toBytes2(bytes memory self, uint256 offset) internal pure returns (bytes2) {
bytes2 out;
for (uint256 i = 0; i < 2; i++) {
out |= bytes2(self[offset + i] & 0xFF) >> (i * 8);
}
return out;
}
function removeLeadingZero(bytes memory data) internal pure returns (bytes memory) {
uint256 length = data.length;
uint256 startIndex = 0;
for (uint256 i = 0; i < length; i++) {
if (data[i] != 0) {
startIndex = i;
break;
}
}
return substr(data, startIndex);
}
function removeEndingZero(bytes memory data) internal pure returns (bytes memory) {
uint256 length = data.length;
uint256 endIndex = 0;
for (uint256 i = length - 1; i >= 0; i--) {
if (data[i] != 0) {
endIndex = i;
break;
}
}
return substr(data, 0, endIndex + 1);
}
function reverse(bytes memory inbytes) internal pure returns (bytes memory) {
uint256 inlength = inbytes.length;
bytes memory outbytes = new bytes(inlength);
for (uint256 i = 0; i <= inlength - 1; i++) {
outbytes[i] = inbytes[inlength - i - 1];
}
return outbytes;
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.17;
// The state commiment identifies a commiment to some intermediate state in the state machine.
// This contains some metadata about the state machine like it's own timestamp at the time of this commitment.
struct StateCommitment {
// This timestamp is useful for handling request timeouts.
uint256 timestamp;
// Overlay trie commitment to all ismp requests & response.
bytes32 overlayRoot;
// State trie commitment at the given block height
bytes32 stateRoot;
}
// Identifies some state machine height. We allow for a state machine identifier here
// as some consensus clients may track multiple, concurrent state machines.
struct StateMachineHeight {
// the state machine identifier
uint256 stateMachineId;
// height of this state machine
uint256 height;
}
// An intermediate state in the series of state transitions undergone by a given state machine.
struct IntermediateState {
// the state machine identifier
uint256 stateMachineId;
// height of this state machine
uint256 height;
// state commitment
StateCommitment commitment;
}
// The consensus client interface responsible for the verification of consensus datagrams.
// It's internals is opaque to the ISMP framework allowing it to evolve as needed.
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} from "./IIsmpHost.sol";
import {
PostRequestMessage,
PostResponseMessage,
GetResponseMessage,
PostRequestTimeoutMessage,
PostResponseTimeoutMessage,
GetTimeoutMessage
} from "./Message.sol";
/*
The IHandler interface serves as the entry point for ISMP datagrams, i.e consensus, requests & response messages.
The handler is decoupled from the IsmpHost as it allows for easy upgrading through the cross-chain governor contract.
This way more efficient cryptographic schemes can be employed without cumbersome contract migrations.
*/
interface IHandler {
/**
* @dev Handle an incoming consensus message. This uses the IConsensusClient contract registered on the host to perform the consensus message verification.
* @param host - Ismp host
* @param proof - consensus proof
*/
function handleConsensus(IIsmpHost host, bytes memory proof) external;
/**
* @dev Handles incoming POST requests, check request proofs, message delay and timeouts, then dispatch POST requests to the apropriate contracts.
* @param host - Ismp host
* @param request - batch post requests
*/
function handlePostRequests(IIsmpHost host, PostRequestMessage memory request) external;
/**
* @dev Handles incoming POST responses, check response proofs, message delay and timeouts, then dispatch POST responses to the apropriate contracts.
* @param host - Ismp host
* @param response - batch post responses
*/
function handlePostResponses(IIsmpHost host, PostResponseMessage memory response) external;
/**
* @dev check response proofs, message delay and timeouts, then dispatch get responses to modules
* @param host - Ismp host
* @param message - batch get responses
*/
function handleGetResponses(IIsmpHost host, GetResponseMessage memory message) external;
/**
* @dev check timeout proofs then dispatch to modules
* @param host - Ismp host
* @param message - batch post request timeouts
*/
function handlePostRequestTimeouts(IIsmpHost host, PostRequestTimeoutMessage memory message) external;
/**
* @dev check timeout proofs then dispatch to modules
* @param host - Ismp host
* @param message - batch post response timeouts
*/
function handlePostResponseTimeouts(IIsmpHost host, PostResponseTimeoutMessage memory message) external;
/**
* @dev dispatch to modules
* @param host - Ismp host
* @param message - batch get request timeouts
*/
function handleGetRequestTimeouts(IIsmpHost host, GetTimeoutMessage memory message) external;
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.17;
import {StateCommitment, StateMachineHeight} from "./IConsensusClient.sol";
import {IDispatcher} from "./IDispatcher.sol";
import {PostRequest, PostResponse, GetResponse, PostTimeout, GetRequest} from "./Message.sol";
// Some metadata about the request fee
struct FeeMetadata {
// the relayer fee
uint256 fee;
// user who initiated the request
address sender;
}
struct ResponseReceipt {
// commitment of the response object
bytes32 responseCommitment;
// address of the relayer responsible for this response delivery
address relayer;
}
// The IsmpHost is the core of the interoperable state machine protocol which encapsulates the interfaces
// required for handlers and modules.
interface IIsmpHost is IDispatcher {
/**
* @return the host admin
*/
function admin() external returns (address);
/**
* @return the address of the fee token ERC-20 contract on this state machine
*/
function feeToken() external view returns (address);
/**
* @return the per-byte fee for outgoing requests.
*/
function perByteFee() external view returns (uint256);
/**
* @return the host state machine id
*/
function host() external view returns (bytes memory);
/**
* @return the state machine identifier for the connected hyperbridge instance
*/
function hyperbridge() external view returns (bytes memory);
/**
* @return the host timestamp
*/
function timestamp() external view returns (uint256);
/**
* @return the `frozen` status
*/
function frozen() external view 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 view returns (address);
/**
* @return the last updated time of the consensus client
*/
function consensusUpdateTime() external view returns (uint256);
/**
* @return the latest state machine height for the given stateMachineId. If it returns 0, the state machine is unsupported.
*/
function latestStateMachineHeight(uint256 stateMachineId) external view returns (uint256);
/**
* @return the state of the consensus client
*/
function consensusState() external view returns (bytes memory);
/**
* @param commitment - commitment to the request
* @return relayer address
*/
function requestReceipts(bytes32 commitment) external view returns (address);
/**
* @param commitment - commitment to the request of the response
* @return response receipt
*/
function responseReceipts(bytes32 commitment) external view returns (ResponseReceipt memory);
/**
* @param commitment - commitment to the request
* @return existence status of an outgoing request commitment
*/
function requestCommitments(bytes32 commitment) external view returns (FeeMetadata memory);
/**
* @param commitment - commitment to the response
* @return existence status of an outgoing response commitment
*/
function responseCommitments(bytes32 commitment) external view returns (FeeMetadata memory);
/**
* @return the challenge period
*/
function challengePeriod() external view returns (uint256);
/**
* @return the unstaking period
*/
function unStakingPeriod() external view returns (uint256);
/**
* @dev Store an encoded consensus state
* @param state new consensus state
*/
function storeConsensusState(bytes memory state) external;
/**
* @dev Store the commitment at `state height`
* @param height state machine height
* @param commitment state commitment
*/
function storeStateMachineCommitment(StateMachineHeight memory height, StateCommitment memory commitment)
external;
/**
* @dev Delete the state commitment at given state height.
*/
function deleteStateMachineCommitment(StateMachineHeight memory height, address fisherman) external;
/**
* @dev Dispatch an incoming request to destination module
* @param request - post request
*/
function dispatchIncoming(PostRequest memory request, address relayer) external;
/**
* @dev Dispatch an incoming post response to source module
* @param response - post response
*/
function dispatchIncoming(PostResponse memory response, address relayer) external;
/**
* @dev Dispatch an incoming get response to source module
* @param response - get response
*/
function dispatchIncoming(GetResponse memory response, address relayer) external;
/**
* @dev Dispatch an incoming get timeout to source module
* @param timeout - timed-out get request
*/
function dispatchIncoming(GetRequest memory timeout, FeeMetadata memory meta, bytes32 commitment) external;
/**
* @dev Dispatch an incoming post timeout to source module
* @param timeout - timed-out post request
*/
function dispatchIncoming(PostRequest memory timeout, FeeMetadata memory meta, bytes32 commitment) external;
/**
* @dev Dispatch an incoming post response timeout to source module
* @param timeout - timed-out post response
*/
function dispatchIncoming(PostResponse memory timeout, FeeMetadata memory meta, bytes32 commitment) external;
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.17;
import {StateMachineHeight} from "./IConsensusClient.sol";
import {StorageValue} from "solidity-merkle-trees/MerklePatricia.sol";
struct PostRequest {
// the source state machine of this request
bytes source;
// the destination state machine of this request
bytes dest;
// request nonce
uint64 nonce;
// Module Id of this request origin
bytes from;
// destination module id
bytes to;
// timestamp by which this request times out.
uint64 timeoutTimestamp;
// request body
bytes body;
}
struct GetRequest {
// the source state machine of this request
bytes source;
// the destination state machine of this request
bytes dest;
// request nonce
uint64 nonce;
// Module Id of this request origin
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;
}
struct GetResponse {
// The request that initiated this response
GetRequest request;
// storage values for get response
StorageValue[] values;
}
struct PostResponse {
// The request that initiated this response
PostRequest request;
// bytes for post response
bytes response;
// timestamp by which this response times out.
uint64 timeoutTimestamp;
}
// A post request as a leaf in a merkle tree
struct PostRequestLeaf {
// The request
PostRequest request;
// It's index in the mmr leaves
uint256 index;
// it's k-index
uint256 kIndex;
}
// A post response as a leaf in a merkle tree
struct PostResponseLeaf {
// The response
PostResponse response;
// It's index in the mmr leaves
uint256 index;
// it's k-index
uint256 kIndex;
}
// A merkle mountain range proof.
struct Proof {
// height of the state machine
StateMachineHeight height;
// the multi-proof
bytes32[] multiproof;
// The total number of leaves in the mmr for this proof.
uint256 leafCount;
}
// A message for handling incoming requests
struct PostRequestMessage {
// proof for the requests
Proof proof;
// the requests, contained in a merkle tree leaf
PostRequestLeaf[] requests;
}
// A message for handling incoming GET responses
struct GetResponseMessage {
// the state (merkle-patricia) proof of the get request keys
bytes[] proof;
// the height of the state machine proof
StateMachineHeight height;
// The requests that initiated this response
GetRequest[] requests;
}
struct GetTimeoutMessage {
// requests which have timed-out
GetRequest[] timeouts;
}
struct PostTimeout {
PostRequest request;
}
struct PostRequestTimeoutMessage {
// requests which have timed-out
PostRequest[] timeouts;
// the height of the state machine proof
StateMachineHeight height;
// non-membership proof of the requests
bytes[] proof;
}
struct PostResponseTimeoutMessage {
// responses which have timed-out
PostResponse[] timeouts;
// the height of the state machine proof
StateMachineHeight height;
// non-membership proof of the requests
bytes[] proof;
}
// A message for handling incoming responses
struct PostResponseMessage {
// proof for the responses
Proof proof;
// the responses, contained in a merkle tree leaf
PostResponseLeaf[] responses;
}
library Message {
function timeout(PostRequest memory req) internal pure returns (uint64) {
if (req.timeoutTimestamp == 0) {
return type(uint64).max;
} else {
return req.timeoutTimestamp;
}
}
function timeout(GetRequest memory req) internal pure returns (uint64) {
if (req.timeoutTimestamp == 0) {
return type(uint64).max;
} else {
return req.timeoutTimestamp;
}
}
function timeout(PostResponse memory res) internal pure returns (uint64) {
if (res.timeoutTimestamp == 0) {
return type(uint64).max;
} else {
return res.timeoutTimestamp;
}
}
function encodeRequest(PostRequest memory req) internal pure returns (bytes memory) {
return abi.encodePacked(req.source, req.dest, req.nonce, req.timeoutTimestamp, req.from, req.to, req.body);
}
function hash(PostResponse memory res) internal pure returns (bytes32) {
return keccak256(bytes.concat(encodeRequest(res.request), abi.encodePacked(res.response, res.timeoutTimestamp)));
}
function hash(PostRequest memory req) internal pure returns (bytes32) {
return keccak256(encodeRequest(req));
}
function hash(GetRequest memory req) internal pure returns (bytes32) {
bytes memory keysEncoding = bytes("");
uint256 len = req.keys.length;
for (uint256 i = 0; i < len; i++) {
keysEncoding = bytes.concat(keysEncoding, req.keys[i]);
}
return keccak256(
abi.encodePacked(req.source, req.dest, req.nonce, req.height, req.timeoutTimestamp, req.from, keysEncoding)
);
}
function hash(GetResponse memory res) internal pure returns (bytes32) {
return hash(res.request);
}
}// 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();
uint8 isOdd = uint8(decoded[0].toBytes()[0] >> 4) & 0x01;
//Remove the first byte, which is the prefix and not present in the user provided key
extension.key = NibbleSlice(Bytes.substr(decoded[0].toBytes(), (isOdd + 1) % 2), isOdd);
extension.node = NodeHandle(true, Bytes.toBytes32(data), false, new bytes(0));
return extension;
}
function decodeBranch(NodeKind memory node) external pure returns (Branch memory) {
Branch memory branch;
RLPReader.RLPItem[] memory decoded = node.data.data.toRlpItem().toList();
NodeHandleOption[16] memory childrens;
for (uint256 i = 0; i < 16; i++) {
bytes memory dataAsBytes = decoded[i].toBytes();
if (dataAsBytes.length != 32) {
childrens[i] = NodeHandleOption(false, NodeHandle(false, bytes32(0), false, new bytes(0)));
} else {
bytes32 data = Bytes.toBytes32(dataAsBytes);
childrens[i] = NodeHandleOption(true, NodeHandle(true, data, false, new bytes(0)));
}
}
if (isEmpty(decoded[16].toBytes())) {
branch.value = NodeHandleOption(false, NodeHandle(false, bytes32(0), false, new bytes(0)));
} else {
branch.value = NodeHandleOption(true, NodeHandle(false, bytes32(0), true, decoded[16].toBytes()));
}
branch.children = childrens;
return branch;
}
function isEmpty(bytes memory item) internal pure returns (bool) {
return item.length > 0 && (item[0] == 0xc0 || item[0] == 0x80);
}
}pragma solidity 0.8.17;
// SPDX-License-Identifier: Apache2
library Memory {
uint256 internal constant WORD_SIZE = 32;
// Compares the 'len' bytes starting at address 'addr' in memory with the 'len'
// bytes starting at 'addr2'.
// Returns 'true' if the bytes are the same, otherwise 'false'.
function equals(uint256 addr, uint256 addr2, uint256 len) internal pure returns (bool equal) {
assembly {
equal := eq(keccak256(addr, len), keccak256(addr2, len))
}
}
// Compares the 'len' bytes starting at address 'addr' in memory with the bytes stored in
// 'bts'. It is allowed to set 'len' to a lower value then 'bts.length', in which case only
// the first 'len' bytes will be compared.
// Requires that 'bts.length >= len'
function equals(uint256 addr, uint256 len, bytes memory bts) internal pure returns (bool equal) {
require(bts.length >= len);
uint256 addr2;
assembly {
addr2 := add(bts, /*BYTES_HEADER_SIZE*/ 32)
}
return equals(addr, addr2, len);
}
// Returns a memory pointer to the data portion of the provided bytes array.
function dataPtr(bytes memory bts) internal pure returns (uint256 addr) {
assembly {
addr := add(bts, /*BYTES_HEADER_SIZE*/ 32)
}
}
// Creates a 'bytes memory' variable from the memory address 'addr', with the
// length 'len'. The function will allocate new memory for the bytes array, and
// the 'len bytes starting at 'addr' will be copied into that new memory.
function toBytes(uint256 addr, uint256 len) internal pure returns (bytes memory bts) {
bts = new bytes(len);
uint256 btsptr;
assembly {
btsptr := add(bts, /*BYTES_HEADER_SIZE*/ 32)
}
copy(addr, btsptr, len);
}
// Copies 'self' into a new 'bytes memory'.
// Returns the newly created 'bytes memory'
// The returned bytes will be of length '32'.
function toBytes(bytes32 self) internal pure returns (bytes memory bts) {
bts = new bytes(32);
assembly {
mstore(add(bts, /*BYTES_HEADER_SIZE*/ 32), self)
}
}
// Copy 'len' bytes from memory address 'src', to address 'dest'.
// This function does not check the or destination, it only copies
// the bytes.
function copy(uint256 src, uint256 dest, uint256 len) internal pure {
// Copy word-length chunks while possible
for (; len >= WORD_SIZE; len -= WORD_SIZE) {
assembly {
mstore(dest, mload(src))
}
dest += WORD_SIZE;
src += WORD_SIZE;
}
// Copy remaining bytes
uint256 mask =
len == 0 ? 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff : 256 ** (WORD_SIZE - len) - 1;
assembly {
let srcpart := and(mload(src), not(mask))
let destpart := and(mload(dest), mask)
mstore(dest, or(destpart, srcpart))
}
}
// This function does the same as 'dataPtr(bytes memory)', but will also return the
// length of the provided bytes array.
function fromBytes(bytes memory bts) internal pure returns (uint256 addr, uint256 len) {
len = bts.length;
assembly {
addr := add(bts, /*BYTES_HEADER_SIZE*/ 32)
}
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.17;
import {StateMachineHeight} from "./IConsensusClient.sol";
import {PostRequest} from "./Message.sol";
// An object for dispatching post requests to the IsmpDispatcher
struct DispatchPost {
// bytes representation of the destination state machine
bytes dest;
// the destination module
bytes to;
// the request body
bytes body;
// timeout for this request in seconds
uint64 timeout;
// the amount put up to be paid to the relayer, this is in $DAI and charged to tx.origin
uint256 fee;
// who pays for this request?
address payer;
}
// An object for dispatching get requests to the IsmpDispatcher
struct DispatchGet {
// bytes representation of the destination state machine
bytes dest;
// height at which to read the state machine
uint64 height;
// Storage keys to read
bytes[] keys;
// timeout for this request in seconds
uint64 timeout;
// The initiator of this request
address sender;
// Hyperbridge protocol fees for processing this request.
uint256 fee;
}
struct DispatchPostResponse {
// The request that initiated this response
PostRequest request;
// bytes for post response
bytes response;
// timeout for this response in seconds
uint64 timeout;
// the amount put up to be paid to the relayer, this is in $DAI and charged to tx.origin
uint256 fee;
// who pays for this request?
address payer;
}
// The core ISMP API, IIsmpModules use this interface to send outgoing get/post requests & responses
interface IDispatcher {
/**
* @dev Dispatch a post request to the ISMP router.
* @param request - post request
* @return commitment - the request commitment
*/
function dispatch(DispatchPost memory request) external returns (bytes32 commitment);
/**
* @dev Dispatch a GET request to the ISMP router.
* @param request - get request
* @return commitment - the request commitment
*/
function dispatch(DispatchGet memory request) external returns (bytes32 commitment);
/**
* @dev Provide a response to a previously received request.
* @param response - post response
* @return commitment - the request commitment
*/
function dispatch(DispatchPostResponse memory response) external returns (bytes32 commitment);
}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)) } } } }
// 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/",
"ERC6160/=lib/ERC6160/src/",
"stringutils/=lib/solidity-stringutils/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/",
"solidity-stringutils/=lib/solidity-stringutils/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs"
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "london",
"libraries": {
"lib/solidity-merkle-trees/src/MerklePatricia.sol": {
"MerklePatricia": "0x8a67323ecb5de34a2f6a120382bdc1dccea6abf9"
},
"lib/solidity-merkle-trees/src/trie/ethereum/EthereumTrieDB.sol": {
"EthereumTrieDB": "0xf3d01dae57cf92044b89d0901ae93dcb299ce83b"
},
"src/consensus/Header.sol": {
"HeaderImpl": "0x34bd76385e6ff5b1ebce453fb08e60ad06c5a4ae"
}
}
}Contract ABI
API[{"inputs":[{"internalType":"contract IIsmpHost","name":"host","type":"address"},{"internalType":"bytes","name":"proof","type":"bytes"}],"name":"handleConsensus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IIsmpHost","name":"host","type":"address"},{"components":[{"components":[{"internalType":"bytes","name":"source","type":"bytes"},{"internalType":"bytes","name":"dest","type":"bytes"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"bytes","name":"from","type":"bytes"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"},{"internalType":"bytes[]","name":"keys","type":"bytes[]"},{"internalType":"uint64","name":"height","type":"uint64"}],"internalType":"struct GetRequest[]","name":"timeouts","type":"tuple[]"}],"internalType":"struct GetTimeoutMessage","name":"message","type":"tuple"}],"name":"handleGetRequestTimeouts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IIsmpHost","name":"host","type":"address"},{"components":[{"internalType":"bytes[]","name":"proof","type":"bytes[]"},{"components":[{"internalType":"uint256","name":"stateMachineId","type":"uint256"},{"internalType":"uint256","name":"height","type":"uint256"}],"internalType":"struct StateMachineHeight","name":"height","type":"tuple"},{"components":[{"internalType":"bytes","name":"source","type":"bytes"},{"internalType":"bytes","name":"dest","type":"bytes"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"bytes","name":"from","type":"bytes"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"},{"internalType":"bytes[]","name":"keys","type":"bytes[]"},{"internalType":"uint64","name":"height","type":"uint64"}],"internalType":"struct GetRequest[]","name":"requests","type":"tuple[]"}],"internalType":"struct GetResponseMessage","name":"message","type":"tuple"}],"name":"handleGetResponses","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IIsmpHost","name":"host","type":"address"},{"components":[{"components":[{"internalType":"bytes","name":"source","type":"bytes"},{"internalType":"bytes","name":"dest","type":"bytes"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"bytes","name":"from","type":"bytes"},{"internalType":"bytes","name":"to","type":"bytes"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"},{"internalType":"bytes","name":"body","type":"bytes"}],"internalType":"struct PostRequest[]","name":"timeouts","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"stateMachineId","type":"uint256"},{"internalType":"uint256","name":"height","type":"uint256"}],"internalType":"struct StateMachineHeight","name":"height","type":"tuple"},{"internalType":"bytes[]","name":"proof","type":"bytes[]"}],"internalType":"struct PostRequestTimeoutMessage","name":"message","type":"tuple"}],"name":"handlePostRequestTimeouts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IIsmpHost","name":"host","type":"address"},{"components":[{"components":[{"components":[{"internalType":"uint256","name":"stateMachineId","type":"uint256"},{"internalType":"uint256","name":"height","type":"uint256"}],"internalType":"struct StateMachineHeight","name":"height","type":"tuple"},{"internalType":"bytes32[]","name":"multiproof","type":"bytes32[]"},{"internalType":"uint256","name":"leafCount","type":"uint256"}],"internalType":"struct Proof","name":"proof","type":"tuple"},{"components":[{"components":[{"internalType":"bytes","name":"source","type":"bytes"},{"internalType":"bytes","name":"dest","type":"bytes"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"bytes","name":"from","type":"bytes"},{"internalType":"bytes","name":"to","type":"bytes"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"},{"internalType":"bytes","name":"body","type":"bytes"}],"internalType":"struct PostRequest","name":"request","type":"tuple"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"kIndex","type":"uint256"}],"internalType":"struct PostRequestLeaf[]","name":"requests","type":"tuple[]"}],"internalType":"struct PostRequestMessage","name":"request","type":"tuple"}],"name":"handlePostRequests","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IIsmpHost","name":"host","type":"address"},{"components":[{"components":[{"components":[{"internalType":"bytes","name":"source","type":"bytes"},{"internalType":"bytes","name":"dest","type":"bytes"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"bytes","name":"from","type":"bytes"},{"internalType":"bytes","name":"to","type":"bytes"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"},{"internalType":"bytes","name":"body","type":"bytes"}],"internalType":"struct PostRequest","name":"request","type":"tuple"},{"internalType":"bytes","name":"response","type":"bytes"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"}],"internalType":"struct PostResponse[]","name":"timeouts","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"stateMachineId","type":"uint256"},{"internalType":"uint256","name":"height","type":"uint256"}],"internalType":"struct StateMachineHeight","name":"height","type":"tuple"},{"internalType":"bytes[]","name":"proof","type":"bytes[]"}],"internalType":"struct PostResponseTimeoutMessage","name":"message","type":"tuple"}],"name":"handlePostResponseTimeouts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IIsmpHost","name":"host","type":"address"},{"components":[{"components":[{"components":[{"internalType":"uint256","name":"stateMachineId","type":"uint256"},{"internalType":"uint256","name":"height","type":"uint256"}],"internalType":"struct StateMachineHeight","name":"height","type":"tuple"},{"internalType":"bytes32[]","name":"multiproof","type":"bytes32[]"},{"internalType":"uint256","name":"leafCount","type":"uint256"}],"internalType":"struct Proof","name":"proof","type":"tuple"},{"components":[{"components":[{"components":[{"internalType":"bytes","name":"source","type":"bytes"},{"internalType":"bytes","name":"dest","type":"bytes"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"bytes","name":"from","type":"bytes"},{"internalType":"bytes","name":"to","type":"bytes"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"},{"internalType":"bytes","name":"body","type":"bytes"}],"internalType":"struct PostRequest","name":"request","type":"tuple"},{"internalType":"bytes","name":"response","type":"bytes"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"}],"internalType":"struct PostResponse","name":"response","type":"tuple"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"kIndex","type":"uint256"}],"internalType":"struct PostResponseLeaf[]","name":"responses","type":"tuple[]"}],"internalType":"struct PostResponseMessage","name":"response","type":"tuple"}],"name":"handlePostResponses","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
608060405234801561001057600080fd5b50615019806100206000396000f3fe608060405234801561001057600080fd5b506004361061007d5760003560e01c80638fcfc9471161005b5780638fcfc947146100bd5780639d38eb35146100d0578063bb1689be146100e3578063e407f86b146100f657600080fd5b8063089b174c146100825780634e2def1e1461009757806372becccd146100aa575b600080fd5b610095610090366004613c39565b610109565b005b6100956100a5366004613c39565b6106f3565b6100956100b8366004613c9a565b610cd8565b6100956100cb366004613cdf565b6113a5565b6100956100de366004613c9a565b61160c565b6100956100f1366004613d35565b611c96565b610095610104366004613c39565b612119565b81806001600160a01b031663054f7d9c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610148573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061016c9190613db9565b156101925760405162461bcd60e51b815260040161018990613ddb565b60405180910390fd5b60408051631a880a9360e01b8152602084013560048201529083013560248201526000906001600160a01b03851690631a880a93906044016020604051808303816000875af11580156101e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061020d9190613e05565b6102179042613e34565b90506000846001600160a01b031663f3f480d96040518163ffffffff1660e01b8152600401602060405180830381865afa158015610259573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061027d9190613e05565b905080158061028b57508082115b6102a75760405162461bcd60e51b815260040161018990613e47565b6040805163a70a8c4760e01b8152602086013560048201529085013560248201526000906001600160a01b0387169063a70a8c47906044016060604051808303816000875af11580156102fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103229190613f76565b60408101519091506103465760405162461bcd60e51b815260040161018990613f92565b60006103528680613fda565b9050905060005b818110156106e957600061036d8880613fda565b8381811061037d5761037d614023565b905060200281019061038f9190614039565b610398906141ec565b90506103a3816126f3565b6001600160401b03168460000151116103f65760405162461bcd60e51b815260206004820152601560248201527414995c5d595cdd081b9bdd081d1a5b5959081bdd5d605a1b6044820152606401610189565b600061040182612725565b604051630da2fd1960e21b8152600481018290529091506000906001600160a01b038c169063368bf464906024016040805180830381865afa15801561044b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061046f91906141f8565b60208101519091506001600160a01b031661049c5760405162461bcd60e51b815260040161018990614230565b604080516001808252818301909252600091816020015b60608152602001906001900390816104b35790505090506040518060400160405280600f81526020016e52657175657374526563656970747360881b8152508360405160200161050591815260200190565b60408051601f1981840301815290829052610523929160200161428b565b60405160208183030381529060405281868151811061054457610544614023565b60200260200101819052506000738a67323ecb5de34a2f6a120382bdc1dccea6abf9631475ff4589604001518e80606001906105809190613fda565b866040518563ffffffff1660e01b81526004016105a09493929190614364565b600060405180830381865af41580156105bd573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526105e59190810190614483565b6000815181106105f7576105f7614023565b6020026020010151905061065360006001600160401b0381111561061d5761061d613e8a565b6040519080825280601f01601f191660200182016040528015610647576020820181803683370190505b5060208301519061273e565b61066f5760405162461bcd60e51b81526004016101899061458e565b604051633b43503560e11b81526001600160a01b038e1690637686a06a9061069f90889087908990600401614675565b600060405180830381600087803b1580156106b957600080fd5b505af11580156106cd573d6000803e3d6000fd5b50505050505050505080806106e1906146b8565b915050610359565b5050505050505050565b81806001600160a01b031663054f7d9c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610732573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107569190613db9565b156107735760405162461bcd60e51b815260040161018990613ddb565b60408051631a880a9360e01b81526020840135600482015290830135602482015242906000906001600160a01b03861690631a880a93906044016020604051808303816000875af11580156107cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107f09190613e05565b6107fa9083613e34565b90506000856001600160a01b031663f3f480d96040518163ffffffff1660e01b8152600401602060405180830381865afa15801561083c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108609190613e05565b905080158061086e57508082115b61088a5760405162461bcd60e51b815260040161018990613e47565b6040805163a70a8c4760e01b8152602087013560048201529086013560248201526000906001600160a01b0388169063a70a8c47906044016060604051808303816000875af11580156108e1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109059190613f76565b604001519050806109285760405162461bcd60e51b8152600401610189906146d1565b60006109376060880188613fda565b9150600090506109478880613fda565b61095091614785565b905060005b82811015610ccc57600061096c60608b018b613fda565b8381811061097c5761097c614023565b905060200281019061098e9190614039565b610997906147b2565b9050876109a382612770565b6001600160401b0316116109f95760405162461bcd60e51b815260206004820152601f60248201527f4948616e646c65723a2047455420726571756573742074696d6564206f7574006044820152606401610189565b6000610a048261279d565b604051630da2fd1960e21b8152600481018290529091506000906001600160a01b038e169063368bf464906024016040805180830381865afa158015610a4e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a7291906141f8565b60208101519091506001600160a01b0316610acf5760405162461bcd60e51b815260206004820152601d60248201527f4948616e646c65723a20556e6b6e6f776e2047455420726571756573740000006044820152606401610189565b60405163442b19bf60e11b8152600481018390526000906001600160a01b038f1690638856337e906024016040805180830381865afa158015610b16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b3a91906141f8565b602001516001600160a01b031614610b945760405162461bcd60e51b815260206004820181905260248201527f4948616e646c65723a204475706c69636174652047455420726573706f6e73656044820152606401610189565b6000738a67323ecb5de34a2f6a120382bdc1dccea6abf96355028f6f89888760a0015187604051602001610bca91815260200190565b6040516020818303038152906040526040518563ffffffff1660e01b8152600401610bf8949392919061489b565b600060405180830381865af4158015610c15573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610c3d9190810190614483565b60408051808201909152858152602081018290529091506001600160a01b038f1663fc17f34082336040518363ffffffff1660e01b8152600401610c8292919061497a565b600060405180830381600087803b158015610c9c57600080fd5b505af1158015610cb0573d6000803e3d6000fd5b5050505050505050508080610cc4906146b8565b915050610955565b50505050505050505050565b81806001600160a01b031663054f7d9c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d3b9190613db9565b15610d585760405162461bcd60e51b815260040161018990613ddb565b4260006001600160a01b038516631a880a93610d748680614a38565b60405160e083901b6001600160e01b03191681528135600482015260209091013560248201526044016020604051808303816000875af1158015610dbc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610de09190613e05565b610dea9083613e34565b90506000856001600160a01b031663f3f480d96040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e509190613e05565b9050801580610e5e57508082115b610e7a5760405162461bcd60e51b815260040161018990613e47565b6000610e896020870187613fda565b905090506000816001600160401b03811115610ea757610ea7613e8a565b604051908082528060200260200182016040528015610ef257816020015b6040805160608101825260008082526020808301829052928201528252600019909201910181610ec55790505b50905060005b8281101561117b576000610f0f60208a018a613fda565b83818110610f1f57610f1f614023565b9050602002810190610f319190614a4e565b610f3a90614ae3565b905086610f4a8260000151612869565b6001600160401b031611610fa05760405162461bcd60e51b815260206004820152601c60248201527f4948616e646c65723a20526573706f6e73652074696d6564206f7574000000006044820152606401610189565b805151600090610faf90612725565b604051630da2fd1960e21b8152600481018290529091506000906001600160a01b038d169063368bf464906024016040805180830381865afa158015610ff9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061101d91906141f8565b60208101519091506001600160a01b031661104a5760405162461bcd60e51b815260040161018990614230565b60405163442b19bf60e11b8152600481018390526000906001600160a01b038e1690638856337e906024016040805180830381865afa158015611091573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110b591906141f8565b602001516001600160a01b0316146111195760405162461bcd60e51b815260206004820152602160248201527f4948616e646c65723a204475706c696361746520506f737420726573706f6e736044820152606560f81b6064820152608401610189565b604051806060016040528084604001518152602001846020015181526020016111458560000151612896565b81525085858151811061115a5761115a614023565b60200260200101819052505050508080611173906146b8565b915050610ef8565b5060006001600160a01b03891663a70a8c476111978a80614a38565b60405160e083901b6001600160e01b03191681528135600482015260209091013560248201526044016060604051808303816000875af11580156111df573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112039190613f76565b602001519050806112265760405162461bcd60e51b8152600401610189906146d1565b61128a816112348a80614a38565b611242906040810190613fda565b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525087925061128191508d905080614a38565b606001356128f8565b6112e05760405162461bcd60e51b815260206004820152602160248201527f4948616e646c65723a20496e76616c696420726573706f6e73652070726f6f666044820152607360f81b6064820152608401610189565b60005b83811015610ccc5760006112fa60208b018b613fda565b8381811061130a5761130a614023565b905060200281019061131c9190614a4e565b61132590614ae3565b90508a6001600160a01b031663ab013de182600001516113423390565b6040518363ffffffff1660e01b815260040161135f929190614b8d565b600060405180830381600087803b15801561137957600080fd5b505af115801561138d573d6000803e3d6000fd5b5050505050808061139d906146b8565b9150506112e3565b81806001600160a01b031663054f7d9c6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113e4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114089190613db9565b156114255760405162461bcd60e51b815260040161018990613ddb565b60006114318380613fda565b915042905060005b8281101561160457600061144d8680613fda565b8381811061145d5761145d614023565b905060200281019061146f9190614039565b611478906147b2565b905060006114858261279d565b604051630da2fd1960e21b8152600481018290529091506000906001600160a01b038a169063368bf464906024016040805180830381865afa1580156114cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114f391906141f8565b60208101519091506001600160a01b03166115205760405162461bcd60e51b815260040161018990614230565b61152983612770565b6001600160401b0316851161158c5760405162461bcd60e51b815260206004820152602360248201527f4948616e646c65723a204745542072657175657374206e6f742074696d6564206044820152621bdd5d60ea1b6064820152608401610189565b60405163687cfe6160e11b81526001600160a01b038a169063d0f9fcc2906115bc90869085908790600401614bb7565b600060405180830381600087803b1580156115d657600080fd5b505af11580156115ea573d6000803e3d6000fd5b5050505050505080806115fc906146b8565b915050611439565b505050505050565b81806001600160a01b031663054f7d9c6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561164b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061166f9190613db9565b1561168c5760405162461bcd60e51b815260040161018990613ddb565b4260006001600160a01b038516631a880a936116a88680614a38565b60405160e083901b6001600160e01b03191681528135600482015260209091013560248201526044016020604051808303816000875af11580156116f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117149190613e05565b61171e9083613e34565b90506000856001600160a01b031663f3f480d96040518163ffffffff1660e01b8152600401602060405180830381865afa158015611760573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117849190613e05565b905080158061179257508082115b6117ae5760405162461bcd60e51b815260040161018990613e47565b60006117bd6020870187613fda565b905090506000816001600160401b038111156117db576117db613e8a565b60405190808252806020026020018201604052801561182657816020015b60408051606081018252600080825260208083018290529282015282526000199092019101816117f95790505b50905060005b82811015611acc57600061184360208a018a613fda565b8381811061185357611853614023565b90506020028101906118659190614a4e565b61186e90614bca565b90506118e58a6001600160a01b031663f437bc596040518163ffffffff1660e01b8152600401600060405180830381865afa1580156118b1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526118d99190810190614c06565b8251602001519061273e565b61193f5760405162461bcd60e51b815260206004820152602560248201527f4948616e646c65723a20496e76616c696420726571756573742064657374696e60448201526430ba34b7b760d91b6064820152608401610189565b8661194d82600001516126f3565b6001600160401b0316116119a35760405162461bcd60e51b815260206004820152601b60248201527f4948616e646c65723a20526571756573742074696d6564206f757400000000006044820152606401610189565b60006119b28260000151612725565b604051630cb33d1f60e11b8152600481018290529091506000906001600160a01b038d16906319667a3e90602401602060405180830381865afa1580156119fd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a219190614c3a565b6001600160a01b031614611a775760405162461bcd60e51b815260206004820152601b60248201527f4948616e646c65723a204475706c6963617465207265717565737400000000006044820152606401610189565b6040518060600160405280836040015181526020018360200151815260200182815250848481518110611aac57611aac614023565b602002602001018190525050508080611ac4906146b8565b91505061182c565b5060006001600160a01b03891663a70a8c47611ae88a80614a38565b60405160e083901b6001600160e01b03191681528135600482015260209091013560248201526044016060604051808303816000875af1158015611b30573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b549190613f76565b60200151905080611b775760405162461bcd60e51b8152600401610189906146d1565b611b85816112348a80614a38565b611bd15760405162461bcd60e51b815260206004820181905260248201527f4948616e646c65723a20496e76616c696420726571756573742070726f6f66736044820152606401610189565b60005b83811015610ccc576000611beb60208b018b613fda565b83818110611bfb57611bfb614023565b9050602002810190611c0d9190614a4e565b611c1690614bca565b90508a6001600160a01b031663b85e6fbb8260000151611c333390565b6040518363ffffffff1660e01b8152600401611c50929190614c57565b600060405180830381600087803b158015611c6a57600080fd5b505af1158015611c7e573d6000803e3d6000fd5b50505050508080611c8e906146b8565b915050611bd4565b82806001600160a01b031663054f7d9c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611cd5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cf99190613db9565b15611d165760405162461bcd60e51b815260040161018990613ddb565b6000846001600160a01b0316639a8425bc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d56573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d7a9190613e05565b611d849042613e34565b9050846001600160a01b031663d40784c76040518163ffffffff1660e01b8152600401602060405180830381865afa158015611dc4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611de89190613e05565b8110611e485760405162461bcd60e51b815260206004820152602960248201527f4948616e646c65723a20636f6e73656e73757320636c69656e74206973206e6f6044820152681dc8195e1c1a5c995960ba1b6064820152608401610189565b600080866001600160a01b0316632476132b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e89573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ead9190614c3a565b6001600160a01b0316637d755598886001600160a01b031663bbad99d46040518163ffffffff1660e01b8152600401600060405180830381865afa158015611ef9573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611f219190810190614c06565b88886040518463ffffffff1660e01b8152600401611f4193929190614c6a565b6000604051808303816000875af1158015611f60573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611f889190810190614c9a565b604051630b4974cf60e41b815291935091506001600160a01b0388169063b4974cf090611fb9908590600401614d1c565b600060405180830381600087803b158015611fd357600080fd5b505af1158015611fe7573d6000803e3d6000fd5b50508251604051634e04afc360e11b8152600093506001600160a01b038b169250639c095f869161201e9160040190815260200190565b602060405180830381865afa15801561203b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061205f9190613e05565b905080158015906120735750808260200151115b156106e95760408051808201825283518152602080850151818301908152858401518451632acf7f4f60e11b81528451600482015291516024830152805160448301529182015160648201529201516084830152906001600160a01b038a169063559efe9e9060a401600060405180830381600087803b1580156120f657600080fd5b505af115801561210a573d6000803e3d6000fd5b50505050505050505050505050565b81806001600160a01b031663054f7d9c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612158573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061217c9190613db9565b156121995760405162461bcd60e51b815260040161018990613ddb565b60408051631a880a9360e01b8152602084013560048201529083013560248201526000906001600160a01b03851690631a880a93906044016020604051808303816000875af11580156121f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122149190613e05565b61221e9042613e34565b90506000846001600160a01b031663f3f480d96040518163ffffffff1660e01b8152600401602060405180830381865afa158015612260573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122849190613e05565b905080158061229257508082115b6122ae5760405162461bcd60e51b815260040161018990613e47565b6040805163a70a8c4760e01b8152602086013560048201529085013560248201526000906001600160a01b0387169063a70a8c47906044016060604051808303816000875af1158015612305573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123299190613f76565b604081015190915061234d5760405162461bcd60e51b815260040161018990613f92565b60006123598680613fda565b9050905060005b818110156106e95760006123748880613fda565b8381811061238457612384614023565b90506020028101906123969190614a4e565b61239f90614d2f565b90506123aa81612869565b6001600160401b03168460000151116124055760405162461bcd60e51b815260206004820181905260248201527f4948616e646c65723a20526573706f6e7365206e6f742074696d6564206f75746044820152606401610189565b600061241082612896565b604051632211f1dd60e01b8152600481018290529091506000906001600160a01b038c1690632211f1dd906024016040805180830381865afa15801561245a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061247e91906141f8565b60208101519091506001600160a01b03166124db5760405162461bcd60e51b815260206004820152601a60248201527f4948616e646c65723a20556e6b6e6f776e20726573706f6e73650000000000006044820152606401610189565b604080516001808252818301909252600091816020015b60608152602001906001900390816124f25790505090506040518060400160405280601081526020016f526573706f6e7365526563656970747360801b8152508360405160200161254591815260200190565b60408051601f1981840301815290829052612563929160200161428b565b60405160208183030381529060405281868151811061258457612584614023565b60200260200101819052506000738a67323ecb5de34a2f6a120382bdc1dccea6abf9631475ff4589604001518e80606001906125c09190613fda565b866040518563ffffffff1660e01b81526004016125e09493929190614364565b600060405180830381865af41580156125fd573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526126259190810190614483565b60008151811061263757612637614023565b6020026020010151905061265d60006001600160401b0381111561061d5761061d613e8a565b6126795760405162461bcd60e51b81526004016101899061458e565b6040516313a6dd3b60e21b81526001600160a01b038e1690634e9b74ec906126a990889087908990600401614d3b565b600060405180830381600087803b1580156126c357600080fd5b505af11580156126d7573d6000803e3d6000fd5b50505050505050505080806126eb906146b8565b915050612360565b60008160a001516001600160401b031660000361271857506001600160401b03919050565b5060a0015190565b919050565b600061273082612910565b805190602001209050919050565b600081518351146127515750600061276a565b825160208381018281209186019283209091145b925050505b92915050565b600081608001516001600160401b031660000361279557506001600160401b03919050565b506080015190565b6040805160208101909152600080825260a083015151909190825b8181101561281457828560a0015182815181106127d7576127d7614023565b60200260200101516040516020016127f092919061428b565b6040516020818303038152906040529250808061280c906146b8565b9150506127b8565b508360000151846020015185604001518660c00151876080015188606001518760405160200161284a9796959493929190614d4e565b6040516020818303038152906040528051906020012092505050919050565b600081604001516001600160401b031660000361288e57506001600160401b03919050565b506040015190565b60006128a58260000151612910565b60208084015160408086015190516128bd9301614dd9565b60408051601f19818403018152908290526128db929160200161428b565b604051602081830303815290604052805190602001209050919050565b6000612905848484612961565b909414949350505050565b60608160000151826020015183604001518460a00151856060015186608001518760c0015160405160200161294b9796959493929190614e0b565b6040516020818303038152906040529050919050565b6000816001148015612974575082516001145b801561299e57508260008151811061298e5761298e614023565b6020026020010151602001516000145b156129c957826000815181106129b6576129b6614023565b6020026020010151604001519050612c28565b60006129d483612c2f565b90506000815190506000604051806040016040528060008152602001836001600160401b03811115612a0857612a08613e8a565b604051908082528060200260200182016040528015612a31578160200160208202803683370190505b509052604080518082019091526000808252602082018a905291925090805b84811015612b77576000868281518110612a6c57612a6c614023565b60200260200101519050806002612a839190614f86565b612a8d9084614f92565b604080516000808252602082019092529194509081612ad4565b6040805160608101825260008082526020808301829052928201528252600019909201910181612aa75790505b508b5190915015612aee57612ae98b85612cd2565b9b5090505b8051600003612b2257845160208601515103612b0b575050612b77565b612b1d86612b1887612ed1565b612f08565b612b6d565b80516001148015612b31575081155b15612b5e57612b1d8682600081518110612b4d57612b4d614023565b602002602001015160400151612f08565b612b6d86612b18838886612f38565b5050600101612a50565b5082516000190183525b825115612c01576000612b9384613115565b90506000612ba085613115565b855160010186526040805160208101859052908101829052909150606001604051602081830303815290604052805190602001208560200151866000015181518110612bee57612bee614023565b6020026020010181815250505050612b81565b8260200151600081518110612c1857612c18614023565b6020026020010151955050505050505b9392505050565b6040805181815261082081018252606091906000908260208201610800803683370190505090506000845b83821015612cb6578015612cb6576000612c738261314d565b905080848481518110612c8857612c88614023565b6020908102919091010152612c9e816002614f86565b612ca89083613e34565b915082600101925050612c5a565b6000612cc28386613e34565b8451038452509195945050505050565b606080600080855190505b80821015612d1c57858281518110612cf757612cf7614023565b602002602001015160200151851115612d1c5781612d14816146b8565b925050612cdd565b60008215612d2a5782612d2d565b60005b90506000816001600160401b03811115612d4957612d49613e8a565b604051908082528060200260200182016040528015612d9457816020015b6040805160608101825260008082526020808301829052928201528252600019909201910181612d675790505b5090506000612da38385613e34565b6001600160401b03811115612dba57612dba613e8a565b604051908082528060200260200182016040528015612e0557816020015b6040805160608101825260008082526020808301829052928201528252600019909201910181612dd85790505b5082519091506000905b80821015612e5f578a8281518110612e2957612e29614023565b6020026020010151848381518110612e4357612e43614023565b602002602001018190525081612e58906146b8565b9150612e0f565b60005b86831015612ebd578b8381518110612e7c57612e7c614023565b6020026020010151848281518110612e9657612e96614023565b602002602001018190525082612eab906146b8565b9250612eb6816146b8565b9050612e62565b5092975090955050505050505b9250929050565b6000808260200151836000015181518110612eee57612eee614023565b602090810291909101015183516001019093525090919050565b808260200151836000015181518110612f2357612f23614023565b60209081029190910101525080516001019052565b6000606080612f46866131e1565b925090506000846001600160401b03811115612f6457612f64613e8a565b604051908082528060200260200182016040528015612f9757816020015b6060815260200190600190039081612f825790505b50905060005b858110156130ff576000612fb18288613e34565b612fbc906002614f86565b905080855103612fcc57506130ff565b6000612fd78661335f565b90506000612fe58288613461565b8051909150806001600160401b0381111561300257613002613e8a565b60405190808252806020026020018201604052801561304757816020015b60408051808201909152600080825260208201528152602001906001900390816130205790505b5086868151811061305a5761305a614023565b602002602001018190525060005b818110156130e457604051806040016040528084838151811061308d5761308d614023565b602002602001015181526020016130a38e612ed1565b8152508787815181106130b8576130b8614023565b602002602001015182815181106130d1576130d1614023565b6020908102919091010152600101613068565b506130ee83613583565b975084600101945050505050612f9d565b5061310a8183613696565b979650505050505050565b600080826020015183600001518151811061313257613132614023565b60209081029190910101518351600019019093525090919050565b600080608083901c1561316257608092831c92015b604083901c1561317457604092831c92015b602083901c1561318657602092831c92015b601083901c1561319857601092831c92015b600883901c156131aa57600892831c92015b600483901c156131bc57600492831c92015b600283901c156131ce57600292831c92015b600183901c1561276a5760010192915050565b606080600080845190506000816001600160401b0381111561320557613205613e8a565b60405190808252806020026020018201604052801561324a57816020015b60408051808201909152600080825260208201528152602001906001900390816132235790505b5090506000826001600160401b0381111561326757613267613e8a565b604051908082528060200260200182016040528015613290578160200160208202803683370190505b5090505b828410156133535760405180604001604052808886815181106132b9576132b9614023565b60200260200101516000015181526020018886815181106132dc576132dc614023565b6020026020010151604001518152508285815181106132fd576132fd614023565b602002602001018190525086848151811061331a5761331a614023565b60200260200101516000015181858151811061333857613338614023565b602090810291909101015261334c846146b8565b9350613294565b90969095509350505050565b80516060906000816001600160401b0381111561337e5761337e613e8a565b6040519080825280602002602001820160405280156133a7578160200160208202803683370190505b50905060005b828110156134595760008582815181106133c9576133c9614023565b6020026020010151905080600003613409576133e6816001614f92565b8383815181106133f8576133f8614023565b602002602001018181525050613450565b613414600282614fbb565b600003613426576133e6816001614f92565b613431600182613e34565b83838151811061344357613443614023565b6020026020010181815250505b506001016133ad565b509392505050565b81518151606091906000826001600160401b0381111561348357613483613e8a565b6040519080825280602002602001820160405280156134ac578160200160208202803683370190505b5090506000805b84811015613565576000805b85811015613511578881815181106134d9576134d9614023565b60200260200101518a84815181106134f3576134f3614023565b6020026020010151036135095760019150613511565b6001016134bf565b508061355c5788828151811061352957613529614023565b602002602001015184848151811061354357613543614023565b602090810291909101015282613558816146b8565b9350505b506001016134b3565b5060006135728286613e34565b835103835250909695505050505050565b80516060906000816001600160401b038111156135a2576135a2613e8a565b6040519080825280602002602001820160405280156135cb578160200160208202803683370190505b5090506000805b8381101561367a57600060028783815181106135f0576135f0614023565b60200260200101516136029190614fcf565b90506000831180156136365750808461361c600186613e34565b8151811061362c5761362c614023565b6020026020010151145b156136415750613668565b8084848151811061365457613654614023565b602002602001018181525050826001019250505b80613672816146b8565b9150506135d2565b5060006136878285613e34565b83510383525090949350505050565b604080516000808252602082019092528190816136d5565b60408051808201909152600080825260208201528152602001906001900390816136ae5790505b5090506136fc83856000815181106136ef576136ef614023565b60200260200101516139c9565b8460008151811061370f5761370f614023565b6020908102919091010152835160005b81811015613991576040805160008082526020820190925281613764565b604080518082019091526000808252602082015281526020019060019003908161373d5790505b50905083516000036137915786828151811061378257613782614023565b602002602001015190506137b7565b6137b48783815181106137a6576137a6614023565b6020026020010151856139c9565b90505b6137c381516002613bd5565b6001600160401b038111156137da576137da613e8a565b60405190808252806020026020018201604052801561381f57816020015b60408051808201909152600080825260208201528152602001906001900390816137f85790505b508151909450600090815b8181101561397a578161383e826001614f92565b106138b257600084828151811061385757613857614023565b6020026020010151905061388985838151811061387657613876614023565b6020026020010151600001516002613bfd565b8152875181908990869081106138a1576138a1614023565b602002602001018190525050613968565b60408051808201909152600080825260208201526138db85838151811061387657613876614023565b8152845161393a908690849081106138f5576138f5614023565b6020026020010151602001518684600161390f9190614f92565b8151811061391f5761391f614023565b60200260200101516020015160009182526020526040902090565b60208201528751819089908690811061395557613955614023565b6020908102919091010152506001909201915b613973600282614f92565b905061382a565b505050508080613989906146b8565b91505061371f565b5081516001146139a057600080fd5b816000815181106139b3576139b3614023565b6020026020010151602001519250505092915050565b8151815160609160009182918291826139e28284614f92565b90506000816001600160401b038111156139fe576139fe613e8a565b604051908082528060200260200182016040528015613a4357816020015b6040805180820190915260008082526020820152815260200190600190039081613a1c5790505b5090505b8387108015613a5557508286105b15613b2a57888681518110613a6c57613a6c614023565b6020026020010151600001518a8881518110613a8a57613a8a614023565b6020026020010151600001511015613ae357898781518110613aae57613aae614023565b6020026020010151818681518110613ac857613ac8614023565b60209081029190910101526001968701969490940193613a47565b888681518110613af557613af5614023565b6020026020010151818681518110613b0f57613b0f614023565b60209081029190910101526001958601959490940193613a47565b83871015613b7957898781518110613b4457613b44614023565b6020026020010151818681518110613b5e57613b5e614023565b60209081029190910101526001968701969490940193613b2a565b82861015613bc857888681518110613b9357613b93614023565b6020026020010151818681518110613bad57613bad614023565b60209081029190910101526001958601959490940193613b79565b9998505050505050505050565b600080613be28385614fcf565b9050613bee8385614fbb565b15612c28576001019392505050565b6000612c288284614fcf565b6001600160a01b0381168114613c1e57600080fd5b50565b600060808284031215613c3357600080fd5b50919050565b60008060408385031215613c4c57600080fd5b8235613c5781613c09565b915060208301356001600160401b03811115613c7257600080fd5b613c7e85828601613c21565b9150509250929050565b600060408284031215613c3357600080fd5b60008060408385031215613cad57600080fd5b8235613cb881613c09565b915060208301356001600160401b03811115613cd357600080fd5b613c7e85828601613c88565b60008060408385031215613cf257600080fd5b8235613cfd81613c09565b915060208301356001600160401b03811115613d1857600080fd5b830160208186031215613d2a57600080fd5b809150509250929050565b600080600060408486031215613d4a57600080fd5b8335613d5581613c09565b925060208401356001600160401b0380821115613d7157600080fd5b818601915086601f830112613d8557600080fd5b813581811115613d9457600080fd5b876020828501011115613da657600080fd5b6020830194508093505050509250925092565b600060208284031215613dcb57600080fd5b81518015158114612c2857600080fd5b60208082526010908201526f24a430b7323632b91d10333937bd32b760811b604082015260600190565b600060208284031215613e1757600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561276a5761276a613e1e565b60208082526023908201527f4948616e646c65723a207374696c6c20696e206368616c6c656e6765207065726040820152621a5bd960ea1b606082015260800190565b634e487b7160e01b600052604160045260246000fd5b604051606081016001600160401b0381118282101715613ec257613ec2613e8a565b60405290565b60405160e081016001600160401b0381118282101715613ec257613ec2613e8a565b604080519081016001600160401b0381118282101715613ec257613ec2613e8a565b604051601f8201601f191681016001600160401b0381118282101715613f3457613f34613e8a565b604052919050565b600060608284031215613f4e57600080fd5b613f56613ea0565b905081518152602082015160208201526040820151604082015292915050565b600060608284031215613f8857600080fd5b612c288383613f3c565b60208082526028908201527f4948616e646c65723a20537461746520436f6d6d69746d656e7420646f65736e60408201526709dd08195e1a5cdd60c21b606082015260800190565b6000808335601e19843603018112613ff157600080fd5b8301803591506001600160401b0382111561400b57600080fd5b6020019150600581901b3603821315612eca57600080fd5b634e487b7160e01b600052603260045260246000fd5b6000823560de1983360301811261404f57600080fd5b9190910192915050565b60006001600160401b0382111561407257614072613e8a565b50601f01601f191660200190565b600082601f83011261409157600080fd5b81356140a461409f82614059565b613f0c565b8181528460208386010111156140b957600080fd5b816020850160208301376000918101602001919091529392505050565b80356001600160401b038116811461272057600080fd5b600060e082840312156140ff57600080fd5b614107613ec8565b905081356001600160401b038082111561412057600080fd5b61412c85838601614080565b8352602084013591508082111561414257600080fd5b61414e85838601614080565b602084015261415f604085016140d6565b6040840152606084013591508082111561417857600080fd5b61418485838601614080565b6060840152608084013591508082111561419d57600080fd5b6141a985838601614080565b60808401526141ba60a085016140d6565b60a084015260c08401359150808211156141d357600080fd5b506141e084828501614080565b60c08301525092915050565b600061276a36836140ed565b60006040828403121561420a57600080fd5b614212613eea565b82518152602083015161422481613c09565b60208201529392505050565b60208082526019908201527f4948616e646c65723a20556e6b6e6f776e207265717565737400000000000000604082015260600190565b60005b8381101561428257818101518382015260200161426a565b50506000910152565b6000835161429d818460208801614267565b8351908301906142b1818360208801614267565b01949350505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b600081518084526142fb816020860160208601614267565b601f01601f19169290920160200192915050565b600081518084526020808501808196508360051b8101915082860160005b858110156143575782840389526143458483516142e3565b9885019893509084019060010161432d565b5091979650505050505050565b60006060820186835260206060818501528186835260808501905060808760051b86010192508760005b888110156143fd57868503607f190183528135368b9003601e190181126143b457600080fd5b8a0184810190356001600160401b038111156143cf57600080fd5b8036038213156143de57600080fd5b6143e98782846142ba565b96505050918301919083019060010161438e565b50505050828103604084015261310a818561430f565b60006001600160401b0382111561442c5761442c613e8a565b5060051b60200190565b600082601f83011261444757600080fd5b815161445561409f82614059565b81815284602083860101111561446a57600080fd5b61447b826020830160208701614267565b949350505050565b6000602080838503121561449657600080fd5b82516001600160401b03808211156144ad57600080fd5b818501915085601f8301126144c157600080fd5b81516144cf61409f82614413565b81815260059190911b830184019084810190888311156144ee57600080fd5b8585015b838110156145815780518581111561450a5760008081fd5b86016040818c03601f19018113156145225760008081fd5b61452a613eea565b898301518881111561453c5760008081fd5b61454a8e8c83870101614436565b8252509082015190878211156145605760008081fd5b61456e8d8b84860101614436565b818b0152855250509186019186016144f2565b5098975050505050505050565b60208082526026908201527f4948616e646c65723a20496e76616c6964206e6f6e2d6d656d6265727368697060408201526510383937b7b360d11b606082015260800190565b6000815160e084526145e960e08501826142e3565b90506020830151848203602086015261460282826142e3565b91505060408301516001600160401b03808216604087015260608501519150858303606087015261463383836142e3565b925060808501519150858303608087015261464e83836142e3565b92508060a08601511660a0870152505060c083015184820360c086015261276582826142e3565b60808152600061468860808301866145d4565b90506146aa6020830185805182526020908101516001600160a01b0316910152565b826060830152949350505050565b6000600182016146ca576146ca613e1e565b5060010190565b60208082526021908201527f4948616e646c65723a2050726f6f6620686569676874206e6f7420666f756e646040820152602160f81b606082015260800190565b600061472061409f84614413565b8381529050602080820190600585901b84018681111561473f57600080fd5b845b8181101561477a5780356001600160401b038111156147605760008081fd5b61476c89828901614080565b855250928201928201614741565b505050509392505050565b6000612c28368484614712565b600082601f8301126147a357600080fd5b612c2883833560208501614712565b600060e082360312156147c457600080fd5b6147cc613ec8565b82356001600160401b03808211156147e357600080fd5b6147ef36838701614080565b8352602085013591508082111561480557600080fd5b61481136838701614080565b6020840152614822604086016140d6565b6040840152606085013591508082111561483b57600080fd5b61484736838701614080565b6060840152614858608086016140d6565b608084015260a085013591508082111561487157600080fd5b5061487e36828601614792565b60a08301525061489060c084016140d6565b60c082015292915050565b8481526080602082015260006148b4608083018661430f565b82810360408401526148c6818661430f565b9050828103606084015261310a81856142e3565b6000815160e084526148ef60e08501826142e3565b90506020830151848203602086015261490882826142e3565b91505060408301516001600160401b03808216604087015260608501519150858303606087015261493983836142e3565b925080608086015116608087015260a0850151915085830360a0870152614960838361430f565b92508060c08601511660c087015250508091505092915050565b600060408083528451818285015261499560808501826148da565b9050602080870151603f198684030160608701528281518085528385019150838160051b860101848401935060005b82811015614a1457868203601f19018452845180518984526149e88a8501826142e3565b91880151848303858a0152919050614a0081836142e3565b9688019695880195935050506001016149c4565b506001600160a01b038a16858a01529650614a2e92505050565b5050509392505050565b60008235607e1983360301811261404f57600080fd5b60008235605e1983360301811261404f57600080fd5b600060608284031215614a7657600080fd5b614a7e613ea0565b905081356001600160401b0380821115614a9757600080fd5b614aa3858386016140ed565b83526020840135915080821115614ab957600080fd5b50614ac684828501614080565b602083015250614ad8604083016140d6565b604082015292915050565b600060608236031215614af557600080fd5b614afd613ea0565b82356001600160401b03811115614b1357600080fd5b614b1f36828601614a64565b825250602083013560208201526040830135604082015280915050919050565b6000815160608452614b5460608501826145d4565b905060208301518482036020860152614b6d82826142e3565b9150506001600160401b0360408401511660408501528091505092915050565b604081526000614ba06040830185614b3f565b905060018060a01b03831660208301529392505050565b60808152600061468860808301866148da565b600060608236031215614bdc57600080fd5b614be4613ea0565b82356001600160401b03811115614bfa57600080fd5b614b1f368286016140ed565b600060208284031215614c1857600080fd5b81516001600160401b03811115614c2e57600080fd5b61447b84828501614436565b600060208284031215614c4c57600080fd5b8151612c2881613c09565b604081526000614ba060408301856145d4565b604081526000614c7d60408301866142e3565b8281036020840152614c908185876142ba565b9695505050505050565b60008082840360c0811215614cae57600080fd5b83516001600160401b03811115614cc457600080fd5b614cd086828701614436565b93505060a0601f1982011215614ce557600080fd5b50614cee613ea0565b6020840151815260408401516020820152614d0c8560608601613f3c565b6040820152809150509250929050565b602081526000612c2860208301846142e3565b600061276a3683614a64565b6080815260006146886080830186614b3f565b60008851614d60818460208d01614267565b885190830190614d74818360208d01614267565b60c089811b6001600160c01b03199081169390920192835288811b8216600884015287901b1660108201528451614db2816018840160208901614267565b8451910190614dc8816018840160208801614267565b016018019998505050505050505050565b60008351614deb818460208801614267565b60c09390931b6001600160c01b0319169190920190815260080192915050565b60008851614e1d818460208d01614267565b885190830190614e31818360208d01614267565b60c089811b6001600160c01b03199081169390920192835288901b1660088201528551614e65816010840160208a01614267565b8551910190614e7b816010840160208901614267565b8451910190614e91816010840160208801614267565b016010019998505050505050505050565b600181815b80851115614edd578160001904821115614ec357614ec3613e1e565b80851615614ed057918102915b93841c9390800290614ea7565b509250929050565b600082614ef45750600161276a565b81614f015750600061276a565b8160018114614f175760028114614f2157614f3d565b600191505061276a565b60ff841115614f3257614f32613e1e565b50506001821b61276a565b5060208310610133831016604e8410600b8410161715614f60575081810a61276a565b614f6a8383614ea2565b8060001904821115614f7e57614f7e613e1e565b029392505050565b6000612c288383614ee5565b8082018082111561276a5761276a613e1e565b634e487b7160e01b600052601260045260246000fd5b600082614fca57614fca614fa5565b500690565b600082614fde57614fde614fa5565b50049056fea2646970667358221220926ca7a03eac3fc216b7e969a9f3748d3b7b8a28a45438023a311e3ba604e88864736f6c63430008110033
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061007d5760003560e01c80638fcfc9471161005b5780638fcfc947146100bd5780639d38eb35146100d0578063bb1689be146100e3578063e407f86b146100f657600080fd5b8063089b174c146100825780634e2def1e1461009757806372becccd146100aa575b600080fd5b610095610090366004613c39565b610109565b005b6100956100a5366004613c39565b6106f3565b6100956100b8366004613c9a565b610cd8565b6100956100cb366004613cdf565b6113a5565b6100956100de366004613c9a565b61160c565b6100956100f1366004613d35565b611c96565b610095610104366004613c39565b612119565b81806001600160a01b031663054f7d9c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610148573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061016c9190613db9565b156101925760405162461bcd60e51b815260040161018990613ddb565b60405180910390fd5b60408051631a880a9360e01b8152602084013560048201529083013560248201526000906001600160a01b03851690631a880a93906044016020604051808303816000875af11580156101e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061020d9190613e05565b6102179042613e34565b90506000846001600160a01b031663f3f480d96040518163ffffffff1660e01b8152600401602060405180830381865afa158015610259573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061027d9190613e05565b905080158061028b57508082115b6102a75760405162461bcd60e51b815260040161018990613e47565b6040805163a70a8c4760e01b8152602086013560048201529085013560248201526000906001600160a01b0387169063a70a8c47906044016060604051808303816000875af11580156102fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103229190613f76565b60408101519091506103465760405162461bcd60e51b815260040161018990613f92565b60006103528680613fda565b9050905060005b818110156106e957600061036d8880613fda565b8381811061037d5761037d614023565b905060200281019061038f9190614039565b610398906141ec565b90506103a3816126f3565b6001600160401b03168460000151116103f65760405162461bcd60e51b815260206004820152601560248201527414995c5d595cdd081b9bdd081d1a5b5959081bdd5d605a1b6044820152606401610189565b600061040182612725565b604051630da2fd1960e21b8152600481018290529091506000906001600160a01b038c169063368bf464906024016040805180830381865afa15801561044b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061046f91906141f8565b60208101519091506001600160a01b031661049c5760405162461bcd60e51b815260040161018990614230565b604080516001808252818301909252600091816020015b60608152602001906001900390816104b35790505090506040518060400160405280600f81526020016e52657175657374526563656970747360881b8152508360405160200161050591815260200190565b60408051601f1981840301815290829052610523929160200161428b565b60405160208183030381529060405281868151811061054457610544614023565b60200260200101819052506000738a67323ecb5de34a2f6a120382bdc1dccea6abf9631475ff4589604001518e80606001906105809190613fda565b866040518563ffffffff1660e01b81526004016105a09493929190614364565b600060405180830381865af41580156105bd573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526105e59190810190614483565b6000815181106105f7576105f7614023565b6020026020010151905061065360006001600160401b0381111561061d5761061d613e8a565b6040519080825280601f01601f191660200182016040528015610647576020820181803683370190505b5060208301519061273e565b61066f5760405162461bcd60e51b81526004016101899061458e565b604051633b43503560e11b81526001600160a01b038e1690637686a06a9061069f90889087908990600401614675565b600060405180830381600087803b1580156106b957600080fd5b505af11580156106cd573d6000803e3d6000fd5b50505050505050505080806106e1906146b8565b915050610359565b5050505050505050565b81806001600160a01b031663054f7d9c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610732573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107569190613db9565b156107735760405162461bcd60e51b815260040161018990613ddb565b60408051631a880a9360e01b81526020840135600482015290830135602482015242906000906001600160a01b03861690631a880a93906044016020604051808303816000875af11580156107cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107f09190613e05565b6107fa9083613e34565b90506000856001600160a01b031663f3f480d96040518163ffffffff1660e01b8152600401602060405180830381865afa15801561083c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108609190613e05565b905080158061086e57508082115b61088a5760405162461bcd60e51b815260040161018990613e47565b6040805163a70a8c4760e01b8152602087013560048201529086013560248201526000906001600160a01b0388169063a70a8c47906044016060604051808303816000875af11580156108e1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109059190613f76565b604001519050806109285760405162461bcd60e51b8152600401610189906146d1565b60006109376060880188613fda565b9150600090506109478880613fda565b61095091614785565b905060005b82811015610ccc57600061096c60608b018b613fda565b8381811061097c5761097c614023565b905060200281019061098e9190614039565b610997906147b2565b9050876109a382612770565b6001600160401b0316116109f95760405162461bcd60e51b815260206004820152601f60248201527f4948616e646c65723a2047455420726571756573742074696d6564206f7574006044820152606401610189565b6000610a048261279d565b604051630da2fd1960e21b8152600481018290529091506000906001600160a01b038e169063368bf464906024016040805180830381865afa158015610a4e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a7291906141f8565b60208101519091506001600160a01b0316610acf5760405162461bcd60e51b815260206004820152601d60248201527f4948616e646c65723a20556e6b6e6f776e2047455420726571756573740000006044820152606401610189565b60405163442b19bf60e11b8152600481018390526000906001600160a01b038f1690638856337e906024016040805180830381865afa158015610b16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b3a91906141f8565b602001516001600160a01b031614610b945760405162461bcd60e51b815260206004820181905260248201527f4948616e646c65723a204475706c69636174652047455420726573706f6e73656044820152606401610189565b6000738a67323ecb5de34a2f6a120382bdc1dccea6abf96355028f6f89888760a0015187604051602001610bca91815260200190565b6040516020818303038152906040526040518563ffffffff1660e01b8152600401610bf8949392919061489b565b600060405180830381865af4158015610c15573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610c3d9190810190614483565b60408051808201909152858152602081018290529091506001600160a01b038f1663fc17f34082336040518363ffffffff1660e01b8152600401610c8292919061497a565b600060405180830381600087803b158015610c9c57600080fd5b505af1158015610cb0573d6000803e3d6000fd5b5050505050505050508080610cc4906146b8565b915050610955565b50505050505050505050565b81806001600160a01b031663054f7d9c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d3b9190613db9565b15610d585760405162461bcd60e51b815260040161018990613ddb565b4260006001600160a01b038516631a880a93610d748680614a38565b60405160e083901b6001600160e01b03191681528135600482015260209091013560248201526044016020604051808303816000875af1158015610dbc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610de09190613e05565b610dea9083613e34565b90506000856001600160a01b031663f3f480d96040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e509190613e05565b9050801580610e5e57508082115b610e7a5760405162461bcd60e51b815260040161018990613e47565b6000610e896020870187613fda565b905090506000816001600160401b03811115610ea757610ea7613e8a565b604051908082528060200260200182016040528015610ef257816020015b6040805160608101825260008082526020808301829052928201528252600019909201910181610ec55790505b50905060005b8281101561117b576000610f0f60208a018a613fda565b83818110610f1f57610f1f614023565b9050602002810190610f319190614a4e565b610f3a90614ae3565b905086610f4a8260000151612869565b6001600160401b031611610fa05760405162461bcd60e51b815260206004820152601c60248201527f4948616e646c65723a20526573706f6e73652074696d6564206f7574000000006044820152606401610189565b805151600090610faf90612725565b604051630da2fd1960e21b8152600481018290529091506000906001600160a01b038d169063368bf464906024016040805180830381865afa158015610ff9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061101d91906141f8565b60208101519091506001600160a01b031661104a5760405162461bcd60e51b815260040161018990614230565b60405163442b19bf60e11b8152600481018390526000906001600160a01b038e1690638856337e906024016040805180830381865afa158015611091573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110b591906141f8565b602001516001600160a01b0316146111195760405162461bcd60e51b815260206004820152602160248201527f4948616e646c65723a204475706c696361746520506f737420726573706f6e736044820152606560f81b6064820152608401610189565b604051806060016040528084604001518152602001846020015181526020016111458560000151612896565b81525085858151811061115a5761115a614023565b60200260200101819052505050508080611173906146b8565b915050610ef8565b5060006001600160a01b03891663a70a8c476111978a80614a38565b60405160e083901b6001600160e01b03191681528135600482015260209091013560248201526044016060604051808303816000875af11580156111df573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112039190613f76565b602001519050806112265760405162461bcd60e51b8152600401610189906146d1565b61128a816112348a80614a38565b611242906040810190613fda565b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525087925061128191508d905080614a38565b606001356128f8565b6112e05760405162461bcd60e51b815260206004820152602160248201527f4948616e646c65723a20496e76616c696420726573706f6e73652070726f6f666044820152607360f81b6064820152608401610189565b60005b83811015610ccc5760006112fa60208b018b613fda565b8381811061130a5761130a614023565b905060200281019061131c9190614a4e565b61132590614ae3565b90508a6001600160a01b031663ab013de182600001516113423390565b6040518363ffffffff1660e01b815260040161135f929190614b8d565b600060405180830381600087803b15801561137957600080fd5b505af115801561138d573d6000803e3d6000fd5b5050505050808061139d906146b8565b9150506112e3565b81806001600160a01b031663054f7d9c6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113e4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114089190613db9565b156114255760405162461bcd60e51b815260040161018990613ddb565b60006114318380613fda565b915042905060005b8281101561160457600061144d8680613fda565b8381811061145d5761145d614023565b905060200281019061146f9190614039565b611478906147b2565b905060006114858261279d565b604051630da2fd1960e21b8152600481018290529091506000906001600160a01b038a169063368bf464906024016040805180830381865afa1580156114cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114f391906141f8565b60208101519091506001600160a01b03166115205760405162461bcd60e51b815260040161018990614230565b61152983612770565b6001600160401b0316851161158c5760405162461bcd60e51b815260206004820152602360248201527f4948616e646c65723a204745542072657175657374206e6f742074696d6564206044820152621bdd5d60ea1b6064820152608401610189565b60405163687cfe6160e11b81526001600160a01b038a169063d0f9fcc2906115bc90869085908790600401614bb7565b600060405180830381600087803b1580156115d657600080fd5b505af11580156115ea573d6000803e3d6000fd5b5050505050505080806115fc906146b8565b915050611439565b505050505050565b81806001600160a01b031663054f7d9c6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561164b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061166f9190613db9565b1561168c5760405162461bcd60e51b815260040161018990613ddb565b4260006001600160a01b038516631a880a936116a88680614a38565b60405160e083901b6001600160e01b03191681528135600482015260209091013560248201526044016020604051808303816000875af11580156116f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117149190613e05565b61171e9083613e34565b90506000856001600160a01b031663f3f480d96040518163ffffffff1660e01b8152600401602060405180830381865afa158015611760573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117849190613e05565b905080158061179257508082115b6117ae5760405162461bcd60e51b815260040161018990613e47565b60006117bd6020870187613fda565b905090506000816001600160401b038111156117db576117db613e8a565b60405190808252806020026020018201604052801561182657816020015b60408051606081018252600080825260208083018290529282015282526000199092019101816117f95790505b50905060005b82811015611acc57600061184360208a018a613fda565b8381811061185357611853614023565b90506020028101906118659190614a4e565b61186e90614bca565b90506118e58a6001600160a01b031663f437bc596040518163ffffffff1660e01b8152600401600060405180830381865afa1580156118b1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526118d99190810190614c06565b8251602001519061273e565b61193f5760405162461bcd60e51b815260206004820152602560248201527f4948616e646c65723a20496e76616c696420726571756573742064657374696e60448201526430ba34b7b760d91b6064820152608401610189565b8661194d82600001516126f3565b6001600160401b0316116119a35760405162461bcd60e51b815260206004820152601b60248201527f4948616e646c65723a20526571756573742074696d6564206f757400000000006044820152606401610189565b60006119b28260000151612725565b604051630cb33d1f60e11b8152600481018290529091506000906001600160a01b038d16906319667a3e90602401602060405180830381865afa1580156119fd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a219190614c3a565b6001600160a01b031614611a775760405162461bcd60e51b815260206004820152601b60248201527f4948616e646c65723a204475706c6963617465207265717565737400000000006044820152606401610189565b6040518060600160405280836040015181526020018360200151815260200182815250848481518110611aac57611aac614023565b602002602001018190525050508080611ac4906146b8565b91505061182c565b5060006001600160a01b03891663a70a8c47611ae88a80614a38565b60405160e083901b6001600160e01b03191681528135600482015260209091013560248201526044016060604051808303816000875af1158015611b30573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b549190613f76565b60200151905080611b775760405162461bcd60e51b8152600401610189906146d1565b611b85816112348a80614a38565b611bd15760405162461bcd60e51b815260206004820181905260248201527f4948616e646c65723a20496e76616c696420726571756573742070726f6f66736044820152606401610189565b60005b83811015610ccc576000611beb60208b018b613fda565b83818110611bfb57611bfb614023565b9050602002810190611c0d9190614a4e565b611c1690614bca565b90508a6001600160a01b031663b85e6fbb8260000151611c333390565b6040518363ffffffff1660e01b8152600401611c50929190614c57565b600060405180830381600087803b158015611c6a57600080fd5b505af1158015611c7e573d6000803e3d6000fd5b50505050508080611c8e906146b8565b915050611bd4565b82806001600160a01b031663054f7d9c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611cd5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cf99190613db9565b15611d165760405162461bcd60e51b815260040161018990613ddb565b6000846001600160a01b0316639a8425bc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d56573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d7a9190613e05565b611d849042613e34565b9050846001600160a01b031663d40784c76040518163ffffffff1660e01b8152600401602060405180830381865afa158015611dc4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611de89190613e05565b8110611e485760405162461bcd60e51b815260206004820152602960248201527f4948616e646c65723a20636f6e73656e73757320636c69656e74206973206e6f6044820152681dc8195e1c1a5c995960ba1b6064820152608401610189565b600080866001600160a01b0316632476132b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e89573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ead9190614c3a565b6001600160a01b0316637d755598886001600160a01b031663bbad99d46040518163ffffffff1660e01b8152600401600060405180830381865afa158015611ef9573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611f219190810190614c06565b88886040518463ffffffff1660e01b8152600401611f4193929190614c6a565b6000604051808303816000875af1158015611f60573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611f889190810190614c9a565b604051630b4974cf60e41b815291935091506001600160a01b0388169063b4974cf090611fb9908590600401614d1c565b600060405180830381600087803b158015611fd357600080fd5b505af1158015611fe7573d6000803e3d6000fd5b50508251604051634e04afc360e11b8152600093506001600160a01b038b169250639c095f869161201e9160040190815260200190565b602060405180830381865afa15801561203b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061205f9190613e05565b905080158015906120735750808260200151115b156106e95760408051808201825283518152602080850151818301908152858401518451632acf7f4f60e11b81528451600482015291516024830152805160448301529182015160648201529201516084830152906001600160a01b038a169063559efe9e9060a401600060405180830381600087803b1580156120f657600080fd5b505af115801561210a573d6000803e3d6000fd5b50505050505050505050505050565b81806001600160a01b031663054f7d9c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612158573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061217c9190613db9565b156121995760405162461bcd60e51b815260040161018990613ddb565b60408051631a880a9360e01b8152602084013560048201529083013560248201526000906001600160a01b03851690631a880a93906044016020604051808303816000875af11580156121f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122149190613e05565b61221e9042613e34565b90506000846001600160a01b031663f3f480d96040518163ffffffff1660e01b8152600401602060405180830381865afa158015612260573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122849190613e05565b905080158061229257508082115b6122ae5760405162461bcd60e51b815260040161018990613e47565b6040805163a70a8c4760e01b8152602086013560048201529085013560248201526000906001600160a01b0387169063a70a8c47906044016060604051808303816000875af1158015612305573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123299190613f76565b604081015190915061234d5760405162461bcd60e51b815260040161018990613f92565b60006123598680613fda565b9050905060005b818110156106e95760006123748880613fda565b8381811061238457612384614023565b90506020028101906123969190614a4e565b61239f90614d2f565b90506123aa81612869565b6001600160401b03168460000151116124055760405162461bcd60e51b815260206004820181905260248201527f4948616e646c65723a20526573706f6e7365206e6f742074696d6564206f75746044820152606401610189565b600061241082612896565b604051632211f1dd60e01b8152600481018290529091506000906001600160a01b038c1690632211f1dd906024016040805180830381865afa15801561245a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061247e91906141f8565b60208101519091506001600160a01b03166124db5760405162461bcd60e51b815260206004820152601a60248201527f4948616e646c65723a20556e6b6e6f776e20726573706f6e73650000000000006044820152606401610189565b604080516001808252818301909252600091816020015b60608152602001906001900390816124f25790505090506040518060400160405280601081526020016f526573706f6e7365526563656970747360801b8152508360405160200161254591815260200190565b60408051601f1981840301815290829052612563929160200161428b565b60405160208183030381529060405281868151811061258457612584614023565b60200260200101819052506000738a67323ecb5de34a2f6a120382bdc1dccea6abf9631475ff4589604001518e80606001906125c09190613fda565b866040518563ffffffff1660e01b81526004016125e09493929190614364565b600060405180830381865af41580156125fd573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526126259190810190614483565b60008151811061263757612637614023565b6020026020010151905061265d60006001600160401b0381111561061d5761061d613e8a565b6126795760405162461bcd60e51b81526004016101899061458e565b6040516313a6dd3b60e21b81526001600160a01b038e1690634e9b74ec906126a990889087908990600401614d3b565b600060405180830381600087803b1580156126c357600080fd5b505af11580156126d7573d6000803e3d6000fd5b50505050505050505080806126eb906146b8565b915050612360565b60008160a001516001600160401b031660000361271857506001600160401b03919050565b5060a0015190565b919050565b600061273082612910565b805190602001209050919050565b600081518351146127515750600061276a565b825160208381018281209186019283209091145b925050505b92915050565b600081608001516001600160401b031660000361279557506001600160401b03919050565b506080015190565b6040805160208101909152600080825260a083015151909190825b8181101561281457828560a0015182815181106127d7576127d7614023565b60200260200101516040516020016127f092919061428b565b6040516020818303038152906040529250808061280c906146b8565b9150506127b8565b508360000151846020015185604001518660c00151876080015188606001518760405160200161284a9796959493929190614d4e565b6040516020818303038152906040528051906020012092505050919050565b600081604001516001600160401b031660000361288e57506001600160401b03919050565b506040015190565b60006128a58260000151612910565b60208084015160408086015190516128bd9301614dd9565b60408051601f19818403018152908290526128db929160200161428b565b604051602081830303815290604052805190602001209050919050565b6000612905848484612961565b909414949350505050565b60608160000151826020015183604001518460a00151856060015186608001518760c0015160405160200161294b9796959493929190614e0b565b6040516020818303038152906040529050919050565b6000816001148015612974575082516001145b801561299e57508260008151811061298e5761298e614023565b6020026020010151602001516000145b156129c957826000815181106129b6576129b6614023565b6020026020010151604001519050612c28565b60006129d483612c2f565b90506000815190506000604051806040016040528060008152602001836001600160401b03811115612a0857612a08613e8a565b604051908082528060200260200182016040528015612a31578160200160208202803683370190505b509052604080518082019091526000808252602082018a905291925090805b84811015612b77576000868281518110612a6c57612a6c614023565b60200260200101519050806002612a839190614f86565b612a8d9084614f92565b604080516000808252602082019092529194509081612ad4565b6040805160608101825260008082526020808301829052928201528252600019909201910181612aa75790505b508b5190915015612aee57612ae98b85612cd2565b9b5090505b8051600003612b2257845160208601515103612b0b575050612b77565b612b1d86612b1887612ed1565b612f08565b612b6d565b80516001148015612b31575081155b15612b5e57612b1d8682600081518110612b4d57612b4d614023565b602002602001015160400151612f08565b612b6d86612b18838886612f38565b5050600101612a50565b5082516000190183525b825115612c01576000612b9384613115565b90506000612ba085613115565b855160010186526040805160208101859052908101829052909150606001604051602081830303815290604052805190602001208560200151866000015181518110612bee57612bee614023565b6020026020010181815250505050612b81565b8260200151600081518110612c1857612c18614023565b6020026020010151955050505050505b9392505050565b6040805181815261082081018252606091906000908260208201610800803683370190505090506000845b83821015612cb6578015612cb6576000612c738261314d565b905080848481518110612c8857612c88614023565b6020908102919091010152612c9e816002614f86565b612ca89083613e34565b915082600101925050612c5a565b6000612cc28386613e34565b8451038452509195945050505050565b606080600080855190505b80821015612d1c57858281518110612cf757612cf7614023565b602002602001015160200151851115612d1c5781612d14816146b8565b925050612cdd565b60008215612d2a5782612d2d565b60005b90506000816001600160401b03811115612d4957612d49613e8a565b604051908082528060200260200182016040528015612d9457816020015b6040805160608101825260008082526020808301829052928201528252600019909201910181612d675790505b5090506000612da38385613e34565b6001600160401b03811115612dba57612dba613e8a565b604051908082528060200260200182016040528015612e0557816020015b6040805160608101825260008082526020808301829052928201528252600019909201910181612dd85790505b5082519091506000905b80821015612e5f578a8281518110612e2957612e29614023565b6020026020010151848381518110612e4357612e43614023565b602002602001018190525081612e58906146b8565b9150612e0f565b60005b86831015612ebd578b8381518110612e7c57612e7c614023565b6020026020010151848281518110612e9657612e96614023565b602002602001018190525082612eab906146b8565b9250612eb6816146b8565b9050612e62565b5092975090955050505050505b9250929050565b6000808260200151836000015181518110612eee57612eee614023565b602090810291909101015183516001019093525090919050565b808260200151836000015181518110612f2357612f23614023565b60209081029190910101525080516001019052565b6000606080612f46866131e1565b925090506000846001600160401b03811115612f6457612f64613e8a565b604051908082528060200260200182016040528015612f9757816020015b6060815260200190600190039081612f825790505b50905060005b858110156130ff576000612fb18288613e34565b612fbc906002614f86565b905080855103612fcc57506130ff565b6000612fd78661335f565b90506000612fe58288613461565b8051909150806001600160401b0381111561300257613002613e8a565b60405190808252806020026020018201604052801561304757816020015b60408051808201909152600080825260208201528152602001906001900390816130205790505b5086868151811061305a5761305a614023565b602002602001018190525060005b818110156130e457604051806040016040528084838151811061308d5761308d614023565b602002602001015181526020016130a38e612ed1565b8152508787815181106130b8576130b8614023565b602002602001015182815181106130d1576130d1614023565b6020908102919091010152600101613068565b506130ee83613583565b975084600101945050505050612f9d565b5061310a8183613696565b979650505050505050565b600080826020015183600001518151811061313257613132614023565b60209081029190910101518351600019019093525090919050565b600080608083901c1561316257608092831c92015b604083901c1561317457604092831c92015b602083901c1561318657602092831c92015b601083901c1561319857601092831c92015b600883901c156131aa57600892831c92015b600483901c156131bc57600492831c92015b600283901c156131ce57600292831c92015b600183901c1561276a5760010192915050565b606080600080845190506000816001600160401b0381111561320557613205613e8a565b60405190808252806020026020018201604052801561324a57816020015b60408051808201909152600080825260208201528152602001906001900390816132235790505b5090506000826001600160401b0381111561326757613267613e8a565b604051908082528060200260200182016040528015613290578160200160208202803683370190505b5090505b828410156133535760405180604001604052808886815181106132b9576132b9614023565b60200260200101516000015181526020018886815181106132dc576132dc614023565b6020026020010151604001518152508285815181106132fd576132fd614023565b602002602001018190525086848151811061331a5761331a614023565b60200260200101516000015181858151811061333857613338614023565b602090810291909101015261334c846146b8565b9350613294565b90969095509350505050565b80516060906000816001600160401b0381111561337e5761337e613e8a565b6040519080825280602002602001820160405280156133a7578160200160208202803683370190505b50905060005b828110156134595760008582815181106133c9576133c9614023565b6020026020010151905080600003613409576133e6816001614f92565b8383815181106133f8576133f8614023565b602002602001018181525050613450565b613414600282614fbb565b600003613426576133e6816001614f92565b613431600182613e34565b83838151811061344357613443614023565b6020026020010181815250505b506001016133ad565b509392505050565b81518151606091906000826001600160401b0381111561348357613483613e8a565b6040519080825280602002602001820160405280156134ac578160200160208202803683370190505b5090506000805b84811015613565576000805b85811015613511578881815181106134d9576134d9614023565b60200260200101518a84815181106134f3576134f3614023565b6020026020010151036135095760019150613511565b6001016134bf565b508061355c5788828151811061352957613529614023565b602002602001015184848151811061354357613543614023565b602090810291909101015282613558816146b8565b9350505b506001016134b3565b5060006135728286613e34565b835103835250909695505050505050565b80516060906000816001600160401b038111156135a2576135a2613e8a565b6040519080825280602002602001820160405280156135cb578160200160208202803683370190505b5090506000805b8381101561367a57600060028783815181106135f0576135f0614023565b60200260200101516136029190614fcf565b90506000831180156136365750808461361c600186613e34565b8151811061362c5761362c614023565b6020026020010151145b156136415750613668565b8084848151811061365457613654614023565b602002602001018181525050826001019250505b80613672816146b8565b9150506135d2565b5060006136878285613e34565b83510383525090949350505050565b604080516000808252602082019092528190816136d5565b60408051808201909152600080825260208201528152602001906001900390816136ae5790505b5090506136fc83856000815181106136ef576136ef614023565b60200260200101516139c9565b8460008151811061370f5761370f614023565b6020908102919091010152835160005b81811015613991576040805160008082526020820190925281613764565b604080518082019091526000808252602082015281526020019060019003908161373d5790505b50905083516000036137915786828151811061378257613782614023565b602002602001015190506137b7565b6137b48783815181106137a6576137a6614023565b6020026020010151856139c9565b90505b6137c381516002613bd5565b6001600160401b038111156137da576137da613e8a565b60405190808252806020026020018201604052801561381f57816020015b60408051808201909152600080825260208201528152602001906001900390816137f85790505b508151909450600090815b8181101561397a578161383e826001614f92565b106138b257600084828151811061385757613857614023565b6020026020010151905061388985838151811061387657613876614023565b6020026020010151600001516002613bfd565b8152875181908990869081106138a1576138a1614023565b602002602001018190525050613968565b60408051808201909152600080825260208201526138db85838151811061387657613876614023565b8152845161393a908690849081106138f5576138f5614023565b6020026020010151602001518684600161390f9190614f92565b8151811061391f5761391f614023565b60200260200101516020015160009182526020526040902090565b60208201528751819089908690811061395557613955614023565b6020908102919091010152506001909201915b613973600282614f92565b905061382a565b505050508080613989906146b8565b91505061371f565b5081516001146139a057600080fd5b816000815181106139b3576139b3614023565b6020026020010151602001519250505092915050565b8151815160609160009182918291826139e28284614f92565b90506000816001600160401b038111156139fe576139fe613e8a565b604051908082528060200260200182016040528015613a4357816020015b6040805180820190915260008082526020820152815260200190600190039081613a1c5790505b5090505b8387108015613a5557508286105b15613b2a57888681518110613a6c57613a6c614023565b6020026020010151600001518a8881518110613a8a57613a8a614023565b6020026020010151600001511015613ae357898781518110613aae57613aae614023565b6020026020010151818681518110613ac857613ac8614023565b60209081029190910101526001968701969490940193613a47565b888681518110613af557613af5614023565b6020026020010151818681518110613b0f57613b0f614023565b60209081029190910101526001958601959490940193613a47565b83871015613b7957898781518110613b4457613b44614023565b6020026020010151818681518110613b5e57613b5e614023565b60209081029190910101526001968701969490940193613b2a565b82861015613bc857888681518110613b9357613b93614023565b6020026020010151818681518110613bad57613bad614023565b60209081029190910101526001958601959490940193613b79565b9998505050505050505050565b600080613be28385614fcf565b9050613bee8385614fbb565b15612c28576001019392505050565b6000612c288284614fcf565b6001600160a01b0381168114613c1e57600080fd5b50565b600060808284031215613c3357600080fd5b50919050565b60008060408385031215613c4c57600080fd5b8235613c5781613c09565b915060208301356001600160401b03811115613c7257600080fd5b613c7e85828601613c21565b9150509250929050565b600060408284031215613c3357600080fd5b60008060408385031215613cad57600080fd5b8235613cb881613c09565b915060208301356001600160401b03811115613cd357600080fd5b613c7e85828601613c88565b60008060408385031215613cf257600080fd5b8235613cfd81613c09565b915060208301356001600160401b03811115613d1857600080fd5b830160208186031215613d2a57600080fd5b809150509250929050565b600080600060408486031215613d4a57600080fd5b8335613d5581613c09565b925060208401356001600160401b0380821115613d7157600080fd5b818601915086601f830112613d8557600080fd5b813581811115613d9457600080fd5b876020828501011115613da657600080fd5b6020830194508093505050509250925092565b600060208284031215613dcb57600080fd5b81518015158114612c2857600080fd5b60208082526010908201526f24a430b7323632b91d10333937bd32b760811b604082015260600190565b600060208284031215613e1757600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561276a5761276a613e1e565b60208082526023908201527f4948616e646c65723a207374696c6c20696e206368616c6c656e6765207065726040820152621a5bd960ea1b606082015260800190565b634e487b7160e01b600052604160045260246000fd5b604051606081016001600160401b0381118282101715613ec257613ec2613e8a565b60405290565b60405160e081016001600160401b0381118282101715613ec257613ec2613e8a565b604080519081016001600160401b0381118282101715613ec257613ec2613e8a565b604051601f8201601f191681016001600160401b0381118282101715613f3457613f34613e8a565b604052919050565b600060608284031215613f4e57600080fd5b613f56613ea0565b905081518152602082015160208201526040820151604082015292915050565b600060608284031215613f8857600080fd5b612c288383613f3c565b60208082526028908201527f4948616e646c65723a20537461746520436f6d6d69746d656e7420646f65736e60408201526709dd08195e1a5cdd60c21b606082015260800190565b6000808335601e19843603018112613ff157600080fd5b8301803591506001600160401b0382111561400b57600080fd5b6020019150600581901b3603821315612eca57600080fd5b634e487b7160e01b600052603260045260246000fd5b6000823560de1983360301811261404f57600080fd5b9190910192915050565b60006001600160401b0382111561407257614072613e8a565b50601f01601f191660200190565b600082601f83011261409157600080fd5b81356140a461409f82614059565b613f0c565b8181528460208386010111156140b957600080fd5b816020850160208301376000918101602001919091529392505050565b80356001600160401b038116811461272057600080fd5b600060e082840312156140ff57600080fd5b614107613ec8565b905081356001600160401b038082111561412057600080fd5b61412c85838601614080565b8352602084013591508082111561414257600080fd5b61414e85838601614080565b602084015261415f604085016140d6565b6040840152606084013591508082111561417857600080fd5b61418485838601614080565b6060840152608084013591508082111561419d57600080fd5b6141a985838601614080565b60808401526141ba60a085016140d6565b60a084015260c08401359150808211156141d357600080fd5b506141e084828501614080565b60c08301525092915050565b600061276a36836140ed565b60006040828403121561420a57600080fd5b614212613eea565b82518152602083015161422481613c09565b60208201529392505050565b60208082526019908201527f4948616e646c65723a20556e6b6e6f776e207265717565737400000000000000604082015260600190565b60005b8381101561428257818101518382015260200161426a565b50506000910152565b6000835161429d818460208801614267565b8351908301906142b1818360208801614267565b01949350505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b600081518084526142fb816020860160208601614267565b601f01601f19169290920160200192915050565b600081518084526020808501808196508360051b8101915082860160005b858110156143575782840389526143458483516142e3565b9885019893509084019060010161432d565b5091979650505050505050565b60006060820186835260206060818501528186835260808501905060808760051b86010192508760005b888110156143fd57868503607f190183528135368b9003601e190181126143b457600080fd5b8a0184810190356001600160401b038111156143cf57600080fd5b8036038213156143de57600080fd5b6143e98782846142ba565b96505050918301919083019060010161438e565b50505050828103604084015261310a818561430f565b60006001600160401b0382111561442c5761442c613e8a565b5060051b60200190565b600082601f83011261444757600080fd5b815161445561409f82614059565b81815284602083860101111561446a57600080fd5b61447b826020830160208701614267565b949350505050565b6000602080838503121561449657600080fd5b82516001600160401b03808211156144ad57600080fd5b818501915085601f8301126144c157600080fd5b81516144cf61409f82614413565b81815260059190911b830184019084810190888311156144ee57600080fd5b8585015b838110156145815780518581111561450a5760008081fd5b86016040818c03601f19018113156145225760008081fd5b61452a613eea565b898301518881111561453c5760008081fd5b61454a8e8c83870101614436565b8252509082015190878211156145605760008081fd5b61456e8d8b84860101614436565b818b0152855250509186019186016144f2565b5098975050505050505050565b60208082526026908201527f4948616e646c65723a20496e76616c6964206e6f6e2d6d656d6265727368697060408201526510383937b7b360d11b606082015260800190565b6000815160e084526145e960e08501826142e3565b90506020830151848203602086015261460282826142e3565b91505060408301516001600160401b03808216604087015260608501519150858303606087015261463383836142e3565b925060808501519150858303608087015261464e83836142e3565b92508060a08601511660a0870152505060c083015184820360c086015261276582826142e3565b60808152600061468860808301866145d4565b90506146aa6020830185805182526020908101516001600160a01b0316910152565b826060830152949350505050565b6000600182016146ca576146ca613e1e565b5060010190565b60208082526021908201527f4948616e646c65723a2050726f6f6620686569676874206e6f7420666f756e646040820152602160f81b606082015260800190565b600061472061409f84614413565b8381529050602080820190600585901b84018681111561473f57600080fd5b845b8181101561477a5780356001600160401b038111156147605760008081fd5b61476c89828901614080565b855250928201928201614741565b505050509392505050565b6000612c28368484614712565b600082601f8301126147a357600080fd5b612c2883833560208501614712565b600060e082360312156147c457600080fd5b6147cc613ec8565b82356001600160401b03808211156147e357600080fd5b6147ef36838701614080565b8352602085013591508082111561480557600080fd5b61481136838701614080565b6020840152614822604086016140d6565b6040840152606085013591508082111561483b57600080fd5b61484736838701614080565b6060840152614858608086016140d6565b608084015260a085013591508082111561487157600080fd5b5061487e36828601614792565b60a08301525061489060c084016140d6565b60c082015292915050565b8481526080602082015260006148b4608083018661430f565b82810360408401526148c6818661430f565b9050828103606084015261310a81856142e3565b6000815160e084526148ef60e08501826142e3565b90506020830151848203602086015261490882826142e3565b91505060408301516001600160401b03808216604087015260608501519150858303606087015261493983836142e3565b925080608086015116608087015260a0850151915085830360a0870152614960838361430f565b92508060c08601511660c087015250508091505092915050565b600060408083528451818285015261499560808501826148da565b9050602080870151603f198684030160608701528281518085528385019150838160051b860101848401935060005b82811015614a1457868203601f19018452845180518984526149e88a8501826142e3565b91880151848303858a0152919050614a0081836142e3565b9688019695880195935050506001016149c4565b506001600160a01b038a16858a01529650614a2e92505050565b5050509392505050565b60008235607e1983360301811261404f57600080fd5b60008235605e1983360301811261404f57600080fd5b600060608284031215614a7657600080fd5b614a7e613ea0565b905081356001600160401b0380821115614a9757600080fd5b614aa3858386016140ed565b83526020840135915080821115614ab957600080fd5b50614ac684828501614080565b602083015250614ad8604083016140d6565b604082015292915050565b600060608236031215614af557600080fd5b614afd613ea0565b82356001600160401b03811115614b1357600080fd5b614b1f36828601614a64565b825250602083013560208201526040830135604082015280915050919050565b6000815160608452614b5460608501826145d4565b905060208301518482036020860152614b6d82826142e3565b9150506001600160401b0360408401511660408501528091505092915050565b604081526000614ba06040830185614b3f565b905060018060a01b03831660208301529392505050565b60808152600061468860808301866148da565b600060608236031215614bdc57600080fd5b614be4613ea0565b82356001600160401b03811115614bfa57600080fd5b614b1f368286016140ed565b600060208284031215614c1857600080fd5b81516001600160401b03811115614c2e57600080fd5b61447b84828501614436565b600060208284031215614c4c57600080fd5b8151612c2881613c09565b604081526000614ba060408301856145d4565b604081526000614c7d60408301866142e3565b8281036020840152614c908185876142ba565b9695505050505050565b60008082840360c0811215614cae57600080fd5b83516001600160401b03811115614cc457600080fd5b614cd086828701614436565b93505060a0601f1982011215614ce557600080fd5b50614cee613ea0565b6020840151815260408401516020820152614d0c8560608601613f3c565b6040820152809150509250929050565b602081526000612c2860208301846142e3565b600061276a3683614a64565b6080815260006146886080830186614b3f565b60008851614d60818460208d01614267565b885190830190614d74818360208d01614267565b60c089811b6001600160c01b03199081169390920192835288811b8216600884015287901b1660108201528451614db2816018840160208901614267565b8451910190614dc8816018840160208801614267565b016018019998505050505050505050565b60008351614deb818460208801614267565b60c09390931b6001600160c01b0319169190920190815260080192915050565b60008851614e1d818460208d01614267565b885190830190614e31818360208d01614267565b60c089811b6001600160c01b03199081169390920192835288901b1660088201528551614e65816010840160208a01614267565b8551910190614e7b816010840160208901614267565b8451910190614e91816010840160208801614267565b016010019998505050505050505050565b600181815b80851115614edd578160001904821115614ec357614ec3613e1e565b80851615614ed057918102915b93841c9390800290614ea7565b509250929050565b600082614ef45750600161276a565b81614f015750600061276a565b8160018114614f175760028114614f2157614f3d565b600191505061276a565b60ff841115614f3257614f32613e1e565b50506001821b61276a565b5060208310610133831016604e8410600b8410161715614f60575081810a61276a565b614f6a8383614ea2565b8060001904821115614f7e57614f7e613e1e565b029392505050565b6000612c288383614ee5565b8082018082111561276a5761276a613e1e565b634e487b7160e01b600052601260045260246000fd5b600082614fca57614fca614fa5565b500690565b600082614fde57614fde614fa5565b50049056fea2646970667358221220926ca7a03eac3fc216b7e969a9f3748d3b7b8a28a45438023a311e3ba604e88864736f6c63430008110033
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.