Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 38506774 | 2 hrs ago | Contract Creation | 0 ETH |
Cross-Chain Transactions
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:
SP1Beefy
Compiler Version
v0.8.30+commit.73712a01
Optimization Enabled:
Yes with 200 runs
Other Settings:
cancun 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.20;
import {IConsensus, IntermediateState} from "@hyperbridge/core/interfaces/IConsensus.sol";
import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import {ISP1Verifier} from "@sp1-contracts/ISP1Verifier.sol";
import "./Codec.sol";
import "./Types.sol";
/**
* @title The SP1 BEEFY Consensus Client.
* @author Polytope Labs ([email protected])
*
* @notice Similar to the BeefyV1 client but delegates secp256k1 signature verification, authority set membership proof checks
* and mmr leaf to an SP1 program.
*/
contract SP1Beefy is IConsensus, ERC165 {
using HeaderImpl for Header;
// SP1 verification key
bytes32 public immutable _verificationKey;
// Sp1 verifier contract
ISP1Verifier public immutable _verifier;
// Provided authority set id was unknown
error UnknownAuthoritySet();
// Provided consensus proof height is stale
error StaleHeight();
// Genesis block should not be provided
error IllegalGenesisBlock();
constructor(ISP1Verifier verifier, bytes32 verificationKey) {
_verifier = verifier;
_verificationKey = verificationKey;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IConsensus).interfaceId || super.supportsInterface(interfaceId);
}
/*
* @dev Given some opaque consensus proof, produce the new consensus state and newly finalized intermediate states.
*/
function verifyConsensus(bytes calldata encodedState, bytes calldata encodedProof)
external
view
returns (bytes memory, IntermediateState[] memory)
{
BeefyConsensusState memory consensusState = abi.decode(encodedState, (BeefyConsensusState));
(
MiniCommitment memory commitment,
PartialBeefyMmrLeaf memory leaf,
ParachainHeader[] memory headers,
bytes memory plonkProof
) = abi.decode(encodedProof, (MiniCommitment, PartialBeefyMmrLeaf, ParachainHeader[], bytes));
SP1BeefyProof memory proof =
SP1BeefyProof({commitment: commitment, mmrLeaf: leaf, headers: headers, proof: plonkProof});
(BeefyConsensusState memory newState, IntermediateState[] memory intermediates) =
verifyConsensus(consensusState, proof);
return (abi.encode(newState), intermediates);
}
/**
* @dev Verifies an SP1 proof of consensus.
*/
function verifyConsensus(BeefyConsensusState memory trustedState, SP1BeefyProof memory proof)
internal
view
returns (BeefyConsensusState memory, IntermediateState[] memory)
{
MiniCommitment memory commitment = proof.commitment;
if (trustedState.latestHeight >= commitment.blockNumber) revert StaleHeight();
AuthoritySetCommitment memory authority;
if (commitment.validatorSetId == trustedState.nextAuthoritySet.id) {
authority = trustedState.nextAuthoritySet;
} else if (commitment.validatorSetId == trustedState.currentAuthoritySet.id) {
authority = trustedState.currentAuthoritySet;
} else {
revert UnknownAuthoritySet();
}
uint256 headers_len = proof.headers.length;
bytes32[] memory headers = new bytes32[](headers_len);
for (uint256 i = 0; i < headers_len; i++) {
headers[i] = keccak256(proof.headers[i].header);
}
bytes memory publicInputs = abi.encode(
PublicInputs({
authorities_len: authority.len,
authorities_root: authority.root,
headers: headers,
leaf_hash: keccak256(Codec.Encode(proof.mmrLeaf))
})
);
_verifier.verifyProof(_verificationKey, publicInputs, proof.proof);
uint256 statesLen = proof.headers.length;
IntermediateState[] memory intermediates = new IntermediateState[](statesLen);
for (uint256 i = 0; i < statesLen; i++) {
ParachainHeader memory para = proof.headers[i];
Header memory header = Codec.DecodeHeader(para.header);
if (header.number == 0) revert IllegalGenesisBlock();
StateCommitment memory stateCommitment = header.stateCommitment();
IntermediateState memory intermediate =
IntermediateState({stateMachineId: para.id, height: header.number, commitment: stateCommitment});
intermediates[i] = intermediate;
}
if (proof.mmrLeaf.nextAuthoritySet.id > trustedState.nextAuthoritySet.id) {
trustedState.currentAuthoritySet = trustedState.nextAuthoritySet;
trustedState.nextAuthoritySet = proof.mmrLeaf.nextAuthoritySet;
}
trustedState.latestHeight = commitment.blockNumber;
return (trustedState, intermediates);
}
// @dev so these structs are included in the abi
function noOp(SP1BeefyProof memory s, PublicInputs memory p) external pure {}
}// 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;
/**
* @title StateCommitment
* @notice Represents a commitment to an intermediate state in the state machine
* @dev Contains metadata about the state machine including timestamp and merkle roots
*/
struct StateCommitment {
/// @notice Unix timestamp of the state machine at the time of this commitment
/// @dev Used for calculating request timeouts and enforcing time-based logic
uint256 timestamp;
/// @notice Merkle root of the overlay trie containing all ISMP requests and responses
/// @dev Used to verify inclusion proofs for cross-chain messages
bytes32 overlayRoot;
/// @notice Merkle root of the state trie at the given block height
/// @dev Represents the complete state of the state machine at this height
bytes32 stateRoot;
}
/**
* @title StateMachineHeight
* @notice Uniquely identifies a specific height in a state machine
* @dev Consensus clients may track multiple concurrent state machines, hence the need for an identifier
*/
struct StateMachineHeight {
/// @notice Unique identifier for the state machine (e.g., parachain ID, chain ID)
/// @dev Each blockchain or parachain in the network has a unique identifier
uint256 stateMachineId;
/// @notice Block height or number in the state machine
/// @dev Represents the sequential position in the blockchain
uint256 height;
}
/**
* @title IntermediateState
* @notice Represents an intermediate state in the state transition sequence of a state machine
* @dev Used to track finalized states that have been verified through consensus
*/
struct IntermediateState {
/// @notice Unique identifier for the state machine
/// @dev Same as StateMachineHeight.stateMachineId
uint256 stateMachineId;
/// @notice Block height of this intermediate state
/// @dev The specific height at which this state was committed
uint256 height;
/// @notice The state commitment at this height
/// @dev Contains the timestamp and merkle roots for this state
StateCommitment commitment;
}
/**
* @title IConsensus
* @author Polytope Labs ([email protected])
* @notice Interface for consensus verification in the Hyperbridge protocol
* @dev Consensus clients implement this interface to verify state transitions from different chains.
* The internals are intentionally opaque to the ISMP framework, allowing consensus mechanisms
* to evolve independently (e.g., GRANDPA for Polkadot, Sync Committee for Ethereum).
* Different consensus mechanisms can be plugged in as long as they conform to this interface.
*/
interface IConsensus {
/**
* @notice Verifies a consensus proof and returns the updated consensus state
* @dev This function is called by the Handler to verify incoming consensus updates.
* The implementation details vary based on the consensus mechanism being verified.
* @param trustedState The current trusted consensus state (encoded based on consensus type)
* @param proof The consensus proof to be verified (e.g., validator signatures, merkle proofs)
* @return The new consensus state after verification (encoded)
* @return Array of newly finalized intermediate states that can be trusted
*/
function verifyConsensus(bytes memory trustedState, bytes memory proof)
external
returns (bytes memory, IntermediateState[] memory);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*/
abstract contract ERC165 is IERC165 {
/// @inheritdoc IERC165
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/// @title SP1 Verifier Interface
/// @author Succinct Labs
/// @notice This contract is the interface for the SP1 Verifier.
interface ISP1Verifier {
/// @notice Verifies a proof with given public values and vkey.
/// @dev It is expected that the first 4 bytes of proofBytes must match the first 4 bytes of
/// target verifier's VERIFIER_HASH.
/// @param programVKey The verification key for the RISC-V program.
/// @param publicValues The public values encoded as bytes.
/// @param proofBytes The proof of the program execution the SP1 zkVM encoded as bytes.
function verifyProof(
bytes32 programVKey,
bytes calldata publicValues,
bytes calldata proofBytes
) external view;
}
interface ISP1VerifierWithHash is ISP1Verifier {
/// @notice Returns the hash of the verifier.
function VERIFIER_HASH() external pure returns (bytes32);
}// 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 "@polytope-labs/solidity-merkle-trees/src/trie/substrate/ScaleCodec.sol";
import "@polytope-labs/solidity-merkle-trees/src/trie/Bytes.sol";
import "./Header.sol";
import "./Types.sol";
// @dev type encoding stuff
library Codec {
uint8 internal constant DIGEST_ITEM_OTHER = 0;
uint8 internal constant DIGEST_ITEM_CONSENSUS = 4;
uint8 internal constant DIGEST_ITEM_SEAL = 5;
uint8 internal constant DIGEST_ITEM_PRERUNTIME = 6;
uint8 internal constant DIGEST_ITEM_RUNTIME_ENVIRONMENT_UPDATED = 8;
// @dev SCALE-encodes the BEEFY finality commitment
function Encode(Commitment memory commitment) internal pure returns (bytes memory) {
uint256 payloadLen = commitment.payload.length;
bytes memory accumulator = bytes("");
for (uint256 i = 0; i < payloadLen; i++) {
accumulator = bytes.concat(
abi.encodePacked(commitment.payload[i].id), ScaleCodec.encodeBytes(commitment.payload[i].data)
);
}
bytes memory payload = bytes.concat(ScaleCodec.encodeUintCompact(payloadLen), accumulator);
bytes memory rest = bytes.concat(
ScaleCodec.encode32(uint32(commitment.blockNumber)), ScaleCodec.encode64(uint64(commitment.validatorSetId))
);
return bytes.concat(payload, rest);
}
// @dev SCALE-encodes the BEEFY Mmr leaf
function Encode(PartialBeefyMmrLeaf memory leaf) internal pure returns (bytes memory) {
bytes memory first =
bytes.concat(abi.encodePacked(uint8(leaf.version)), ScaleCodec.encode32(uint32(leaf.parentNumber)));
bytes memory second =
bytes.concat(bytes.concat(leaf.parentHash), ScaleCodec.encode64(uint64(leaf.nextAuthoritySet.id)));
bytes memory third = bytes.concat(
ScaleCodec.encode32(uint32(leaf.nextAuthoritySet.len)), bytes.concat(leaf.nextAuthoritySet.root)
);
return bytes.concat(bytes.concat(first, second), bytes.concat(third, bytes.concat(leaf.extra)));
}
// @dev Deserializes a substrate header
function DecodeHeader(bytes memory encoded) internal pure returns (Header memory) {
ByteSlice memory slice = ByteSlice(encoded, 0);
bytes32 parentHash = Bytes.toBytes32(Bytes.read(slice, 32));
uint256 blockNumber = ScaleCodec.decodeUintCompact(slice);
bytes32 stateRoot = Bytes.toBytes32(Bytes.read(slice, 32));
bytes32 extrinsicsRoot = Bytes.toBytes32(Bytes.read(slice, 32));
uint256 length = ScaleCodec.decodeUintCompact(slice);
Digest[] memory digests = new Digest[](length);
for (uint256 i = 0; i < length; i++) {
uint8 kind = Bytes.readByte(slice);
Digest memory digest;
if (kind == DIGEST_ITEM_OTHER) {
digest.isOther = true;
} else if (kind == DIGEST_ITEM_CONSENSUS) {
digest.isConsensus = true;
digest.consensus = decodeDigestItem(slice);
} else if (kind == DIGEST_ITEM_SEAL) {
digest.isSeal = true;
digest.seal = decodeDigestItem(slice);
} else if (kind == DIGEST_ITEM_PRERUNTIME) {
digest.isPreRuntime = true;
digest.preruntime = decodeDigestItem(slice);
} else if (kind == DIGEST_ITEM_RUNTIME_ENVIRONMENT_UPDATED) {
digest.isRuntimeEnvironmentUpdated = true;
}
digests[i] = digest;
}
return Header(parentHash, blockNumber, stateRoot, extrinsicsRoot, digests);
}
function decodeDigestItem(ByteSlice memory slice) internal pure returns (DigestItem memory) {
bytes4 id = Bytes.toBytes4(read(slice, 4), 0);
uint256 length = ScaleCodec.decodeUintCompact(slice);
bytes memory data = Bytes.read(slice, length);
return DigestItem(id, data);
}
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;
}
function readByte(ByteSlice memory self) internal pure returns (uint8) {
require(self.offset + 1 <= self.data.length);
uint8 b = uint8(self.data[self.offset]);
self.offset += 1;
return b;
}
// @dev Decodes a SCALE encoded compact unsigned integer
function decodeUintCompact(ByteSlice memory data) internal pure returns (uint256 v) {
uint8 b = readByte(data); // 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 = 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 = readByte(data); // read the next 3 bytes
uint8 b3 = readByte(data);
uint8 b4 = 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 ScaleCodec.decodeUint256(read(data, l));
} else {
revert("Code should be unreachable");
}
return (value);
}
// @dev Convert the provided type to a bn254 field element
function toFieldElements(bytes32 source) internal pure returns (bytes32, bytes32) {
// is assembly cheaper?
bytes32 left = bytes32(uint256(uint128(bytes16(source))));
bytes32 right = bytes32(uint256(uint128(uint256(source))));
return (left, right);
}
}// 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 {Node} from "@polytope-labs/solidity-merkle-trees/src/Types.sol";
struct SP1BeefyProof {
// BEEFY Commitment message
MiniCommitment commitment;
// Latest leaf added to mmr
PartialBeefyMmrLeaf mmrLeaf;
// Parachain headers finalized by the commitment
ParachainHeader[] headers;
// SP1 plonk proof for BEEFY consensus
bytes proof;
}
struct MiniCommitment {
uint256 blockNumber;
uint256 validatorSetId;
}
struct ParachainHeader {
/// Parachain Id
uint256 id;
/// SCALE encoded header
bytes header;
}
/// The public values encoded as a struct that can be easily deserialized inside Solidity.
struct PublicInputs {
// merkle commitment to all authorities
bytes32 authorities_root;
// size of the authority set
uint256 authorities_len;
// BEEFY mmr leaf hash
bytes32 leaf_hash;
// Parachain header hashes
bytes32[] headers;
}
struct Payload {
bytes2 id;
bytes data;
}
struct Commitment {
Payload[] payload;
uint256 blockNumber;
uint256 validatorSetId;
}
struct AuthoritySetCommitment {
/// Id of the set.
uint256 id;
/// Number of validators in the set.
uint256 len;
/// Merkle Root Hash built from BEEFY AuthorityIds.
bytes32 root;
}
struct BeefyMmrLeaf {
uint256 version;
uint256 parentNumber;
bytes32 parentHash;
AuthoritySetCommitment nextAuthoritySet;
bytes32 extra;
uint256 kIndex;
uint256 leafIndex;
}
struct BeefyConsensusState {
/// block number for the latest mmr_root_hash
uint256 latestHeight;
/// Block number that the beefy protocol was activated on the relay chain.
/// This should be the first block in the merkle-mountain-range tree.
uint256 beefyActivationBlock;
/// authorities for the current round
AuthoritySetCommitment currentAuthoritySet;
/// authorities for the next round
AuthoritySetCommitment nextAuthoritySet;
}
struct PartialBeefyMmrLeaf {
uint256 version;
uint256 parentNumber;
bytes32 parentHash;
AuthoritySetCommitment nextAuthoritySet;
bytes32 extra;
}
struct Parachain {
/// k-index for latestHeadsRoot
uint256 index;
/// Parachain Id
uint256 id;
/// SCALE encoded header
bytes header;
}
struct ParachainProof {
Parachain parachain;
Node[][] proof;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol)
pragma solidity >=0.4.16;
/**
* @dev Interface of the ERC-165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[ERC].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// 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.20;
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);
}
}// 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.20;
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;
}
}// 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 {StateCommitment} from "@hyperbridge/core/interfaces/IConsensus.sol";
import "@polytope-labs/solidity-merkle-trees/src/trie/Bytes.sol";
import "@polytope-labs/solidity-merkle-trees/src/trie/substrate/ScaleCodec.sol";
struct DigestItem {
bytes4 consensusId;
bytes data;
}
struct Digest {
bool isPreRuntime;
DigestItem preruntime;
bool isConsensus;
DigestItem consensus;
bool isSeal;
DigestItem seal;
bool isOther;
bytes other;
bool isRuntimeEnvironmentUpdated;
}
struct Header {
bytes32 parentHash;
uint256 number;
bytes32 stateRoot;
bytes32 extrinsicRoot;
Digest[] digests;
}
library HeaderImpl {
/// Digest Item ID
bytes4 public constant ISMP_CONSENSUS_ID = bytes4("ISMP");
/// ConsensusID for aura
bytes4 public constant AURA_CONSENSUS_ID = bytes4("aura");
/// Slot duration in milliseconds
uint256 public constant SLOT_DURATION = 12000;
error TimestampNotFound();
error ChildTrieRootNotFound();
// Extracts the `StateCommitment` from the provided header.
function stateCommitment(Header calldata self) public pure returns (StateCommitment memory) {
bytes32 mmrRoot;
bytes32 childTrieRoot;
uint256 timestamp;
for (uint256 j = 0; j < self.digests.length; j++) {
if (self.digests[j].isConsensus && self.digests[j].consensus.consensusId == ISMP_CONSENSUS_ID) {
mmrRoot = Bytes.toBytes32(self.digests[j].consensus.data[:32]);
childTrieRoot = Bytes.toBytes32(self.digests[j].consensus.data[32:]);
}
if (self.digests[j].isPreRuntime && self.digests[j].preruntime.consensusId == AURA_CONSENSUS_ID) {
uint256 slot = ScaleCodec.decodeUint256(self.digests[j].preruntime.data);
timestamp = slot * SLOT_DURATION;
}
}
// sanity check
if (timestamp == 0) revert TimestampNotFound();
if (childTrieRoot == bytes32(0)) revert ChildTrieRootNotFound();
return StateCommitment({timestamp: timestamp, overlayRoot: mmrRoot, stateRoot: childTrieRoot});
}
}// 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.20;
// Outcome of a successfully verified merkle-patricia proof
struct StorageValue {
// the storage key
bytes key;
// the encoded value
bytes value;
}
/// @title A representation of a Merkle tree node
struct Node {
// Distance of the node to the leftmost node
uint256 k_index;
// A hash of the node itself
bytes32 node;
}
/// @title A representation of a MerkleMountainRange leaf
struct MmrLeaf {
// the leftmost index of a node
uint256 k_index;
// The position in the tree
uint256 leaf_index;
// The hash of the position in the tree
bytes32 hash;
}
struct Iterator {
uint256 offset;
bytes32[] data;
}// 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.20;
library Memory {
uint256 internal constant WORD_SIZE = 32;
// Compares the 'len' bytes starting at address 'addr' in memory with the 'len'
// bytes starting at 'addr2'.
// Returns 'true' if the bytes are the same, otherwise 'false'.
function equals(
uint256 addr,
uint256 addr2,
uint256 len
) internal pure returns (bool equal) {
assembly {
equal := eq(keccak256(addr, len), keccak256(addr2, len))
}
}
// Compares the 'len' bytes starting at address 'addr' in memory with the bytes stored in
// 'bts'. It is allowed to set 'len' to a lower value then 'bts.length', in which case only
// the first 'len' bytes will be compared.
// Requires that 'bts.length >= len'
function equals(
uint256 addr,
uint256 len,
bytes memory bts
) internal pure returns (bool equal) {
require(bts.length >= len);
uint256 addr2;
assembly {
addr2 := add(bts, /*BYTES_HEADER_SIZE*/ 32)
}
return equals(addr, addr2, len);
}
// Returns a memory pointer to the data portion of the provided bytes array.
function dataPtr(bytes memory bts) internal pure returns (uint256 addr) {
assembly {
addr := add(bts, /*BYTES_HEADER_SIZE*/ 32)
}
}
// Creates a 'bytes memory' variable from the memory address 'addr', with the
// length 'len'. The function will allocate new memory for the bytes array, and
// the 'len bytes starting at 'addr' will be copied into that new memory.
function toBytes(
uint256 addr,
uint256 len
) internal pure returns (bytes memory bts) {
bts = new bytes(len);
uint256 btsptr;
assembly {
btsptr := add(bts, /*BYTES_HEADER_SIZE*/ 32)
}
copy(addr, btsptr, len);
}
// Copies 'self' into a new 'bytes memory'.
// Returns the newly created 'bytes memory'
// The returned bytes will be of length '32'.
function toBytes(bytes32 self) internal pure returns (bytes memory bts) {
bts = new bytes(32);
assembly {
mstore(add(bts, /*BYTES_HEADER_SIZE*/ 32), self)
}
}
// Copy 'len' bytes from memory address 'src', to address 'dest'.
// This function does not check the or destination, it only copies
// the bytes.
function copy(uint256 src, uint256 dest, uint256 len) internal pure {
// Copy word-length chunks while possible
for (; len >= WORD_SIZE; len -= WORD_SIZE) {
assembly {
mstore(dest, mload(src))
}
dest += WORD_SIZE;
src += WORD_SIZE;
}
// Copy remaining bytes
uint256 mask = len == 0
? 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
: 256 ** (WORD_SIZE - len) - 1;
assembly {
let srcpart := and(mload(src), not(mask))
let destpart := and(mload(dest), mask)
mstore(dest, or(destpart, srcpart))
}
}
// This function does the same as 'dataPtr(bytes memory)', but will also return the
// length of the provided bytes array.
function fromBytes(
bytes memory bts
) internal pure returns (uint256 addr, uint256 len) {
len = bts.length;
assembly {
addr := add(bts, /*BYTES_HEADER_SIZE*/ 32)
}
}
}{
"remappings": [
"@hyperbridge/core/=node_modules/@hyperbridge/core/contracts/",
"@openzeppelin/=node_modules/@openzeppelin/",
"@polytope-labs/=node_modules/@polytope-labs/",
"@uniswap/=node_modules/@uniswap/",
"stringutils/=lib/solidity-stringutils/src/",
"@sp1-contracts/=lib/sp1-contracts/contracts/src/",
"ds-test/=lib/solidity-stringutils/lib/ds-test/src/",
"erc4626-tests/=lib/sp1-contracts/contracts/lib/openzeppelin-contracts/lib/erc4626-tests/",
"forge-std/=lib/forge-std/src/",
"openzeppelin-contracts/=lib/sp1-contracts/contracts/lib/openzeppelin-contracts/",
"solidity-stringutils/=lib/solidity-stringutils/",
"sp1-contracts/=lib/sp1-contracts/contracts/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": true,
"libraries": {
"src/consensus/SP1Beefy.sol": {
"HeaderImpl": "0x2cb960d03080a42ac4d9d53c0cc87cd6795ec9b3"
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract ISP1Verifier","name":"verifier","type":"address"},{"internalType":"bytes32","name":"verificationKey","type":"bytes32"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"IllegalGenesisBlock","type":"error"},{"inputs":[],"name":"StaleHeight","type":"error"},{"inputs":[],"name":"UnknownAuthoritySet","type":"error"},{"inputs":[],"name":"_verificationKey","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_verifier","outputs":[{"internalType":"contract ISP1Verifier","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"uint256","name":"validatorSetId","type":"uint256"}],"internalType":"struct MiniCommitment","name":"commitment","type":"tuple"},{"components":[{"internalType":"uint256","name":"version","type":"uint256"},{"internalType":"uint256","name":"parentNumber","type":"uint256"},{"internalType":"bytes32","name":"parentHash","type":"bytes32"},{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"len","type":"uint256"},{"internalType":"bytes32","name":"root","type":"bytes32"}],"internalType":"struct AuthoritySetCommitment","name":"nextAuthoritySet","type":"tuple"},{"internalType":"bytes32","name":"extra","type":"bytes32"}],"internalType":"struct PartialBeefyMmrLeaf","name":"mmrLeaf","type":"tuple"},{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"header","type":"bytes"}],"internalType":"struct ParachainHeader[]","name":"headers","type":"tuple[]"},{"internalType":"bytes","name":"proof","type":"bytes"}],"internalType":"struct SP1BeefyProof","name":"s","type":"tuple"},{"components":[{"internalType":"bytes32","name":"authorities_root","type":"bytes32"},{"internalType":"uint256","name":"authorities_len","type":"uint256"},{"internalType":"bytes32","name":"leaf_hash","type":"bytes32"},{"internalType":"bytes32[]","name":"headers","type":"bytes32[]"}],"internalType":"struct PublicInputs","name":"p","type":"tuple"}],"name":"noOp","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedState","type":"bytes"},{"internalType":"bytes","name":"encodedProof","type":"bytes"}],"name":"verifyConsensus","outputs":[{"internalType":"bytes","name":"","type":"bytes"},{"components":[{"internalType":"uint256","name":"stateMachineId","type":"uint256"},{"internalType":"uint256","name":"height","type":"uint256"},{"components":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bytes32","name":"overlayRoot","type":"bytes32"},{"internalType":"bytes32","name":"stateRoot","type":"bytes32"}],"internalType":"struct StateCommitment","name":"commitment","type":"tuple"}],"internalType":"struct IntermediateState[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"}]Contract Creation Code
60c03461008a57601f611ab738819003918201601f19168301916001600160401b0383118484101761008e57808492604094855283398101031261008a578051906001600160a01b038216820361008a57602001519060a052608052604051611a1490816100a382396080518181816105180152610c39015260a0518181816107210152610bf30152f35b5f80fd5b634e487b7160e01b5f52604160045260245ffdfe60806040526004361015610011575f80fd5b5f3560e01c806301ffc9a71461006457806309a07dd31461005f5780631a2bd4871461005a5780637d7555981461005557638a17265114610050575f80fd5b61070c565b610604565b610501565b610425565b346100b85760203660031901126100b85760043563ffffffff60e01b81168091036100b857630faeaab360e31b81149081156100a7575b50151560805260206080f35b6301ffc9a760e01b1490508161009b565b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b038211176100eb57604052565b6100bc565b606081019081106001600160401b038211176100eb57604052565b60a081019081106001600160401b038211176100eb57604052565b608081019081106001600160401b038211176100eb57604052565b90601f801991011681019081106001600160401b038211176100eb57604052565b60405190610171608083610141565b565b60405190610171606083610141565b60405190610171604083610141565b6040519061017160a083610141565b91908260409103126100b8576040516101b8816100d0565b6020808294803584520135910152565b91908260609103126100b8576040516101e0816100f0565b604080829480358452602081013560208501520135910152565b91909160e0818403126100b857608060c0604051926102188461010b565b61023e8496823586526020830135602087015260408301356040870152606083016101c8565b60608501520135910152565b6001600160401b0381116100eb5760051b60200190565b6001600160401b0381116100eb57601f01601f191660200190565b81601f820112156100b85780359061029382610261565b926102a16040519485610141565b828452602083830101116100b857815f926020809301838601378301015290565b9080601f830112156100b8578135916102da8361024a565b926102e86040519485610141565b80845260208085019160051b830101918383116100b85760208101915b83831061031457505050505090565b82356001600160401b0381116100b8578201906040828703601f1901126100b85760405190610342826100d0565b602083013582526040830135916001600160401b0383116100b85761036f8860208096958196010161027c565b83820152815201920191610305565b91906080838203126100b85760405161039681610126565b80938035825260208101356020830152604081013560408301526060810135906001600160401b0382116100b857019180601f840112156100b85782356103dc8161024a565b936103ea6040519586610141565b81855260208086019260051b8201019283116100b857602001905b8282106104155750505060600152565b8135815260209182019101610405565b346100b85760403660031901126100b8576004356001600160401b0381116100b85761016060031982360301126100b8576040519061046382610126565b61047036826004016101a0565b825261047f36604483016101fa565b60208301526101248101356001600160401b0381116100b8576104a890600436918401016102c2565b60408301526101448101356001600160401b0381116100b85760609160046104d3923692010161027c565b9101526024356001600160401b0381116100b8576104f590369060040161037e565b005b5f9103126100b857565b346100b8575f3660031901126100b85760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b9181601f840112156100b8578235916001600160401b0383116100b857602083818601950101116100b857565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b9061059f90604083526040830190610568565b906020818303910152602080835192838152019201905f5b8181106105c45750505090565b909192602060a0600192604080885180518452858101518685015201518051828401528481015160608401520151608082015201940191019190916105b7565b346100b85760403660031901126100b8576004356001600160401b0381116100b85761063490369060040161053b565b6024356001600160401b0381116100b85761065390369060040161053b565b9091830192610100818503126100b8576106b76106eb936106da936106aa6106f99760a06040519661068488610126565b803588526020810135602089015261069f83604083016101c8565b6040890152016101c8565b6060850152810190610750565b916106c3949394610162565b948552602085015260408401526060830152610b3f565b9290604051928391602083016107b7565b03601f198101835282610141565b6107086040519283928361058c565b0390f35b346100b8575f3660031901126100b8576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b90610160828203126100b85761076681836101a0565b9261077482604085016101fa565b926101208101356001600160401b0381116100b857836107959183016102c2565b926101408201356001600160401b0381116100b8576107b4920161027c565b90565b6101719092919260a0606061010083019580518452602081015160208501526107fc604082015160408601906040809180518452602081015160208501520151910152565b01519101906040809180518452602081015160208501520151910152565b60405190610827826100f0565b5f6040838281528260208201520152565b6040519061084582610126565b815f81525f602082015261085761081a565b6040820152606061086661081a565b910152565b906108758261024a565b6108826040519182610141565b8281528092610893601f199161024a565b0190602036910137565b634e487b7160e01b5f52603260045260245ffd5b80518210156108c55760209160051b010190565b61089d565b9060208252602060c0606060a08501938051848701528381015160408701526040810151828701520151936080808201528451809452019201905f5b8181106109135750505090565b8251845260209384019390920191600101610906565b91610946906107b494928452606060208501526060840190610568565b916040818403910152610568565b6040513d5f823e3d90fd5b906109698261024a565b6109766040519182610141565b8281528092610987601f199161024a565b01905f5b82811061099757505050565b6020906040516109a6816100f0565b5f81525f838201526109b661081a565b60408201528282850101520161098b565b908160609103126100b85760408051916109e0836100f0565b80518352602081015160208401520151604082015290565b90604060206107b49363ffffffff60e01b81511684520151918160208201520190610568565b60208152608060c082019280516020840152602081015160408401526040810151606084015260608101518284015201519160a080830152825180915260e0820191602060e08360051b8301019401925f915b838310610a8057505050505090565b909192939460208060019260df19858203018652610b30895191610aa681845115159052565b61010080610b26610b08610aea610acc898901516101208b8901526101208801906109f8565b604089810151151590880152606089015187820360608901526109f8565b60808881015115159087015260a088015186820360a08801526109f8565b60c08781015115159086015260e087015185820360e0870152610568565b9401511515910152565b97019301930191939290610a71565b919091610b4a610838565b508251815181511115610e1357610b5f61081a565b506020810151606083019081515181145f14610def575080515b6040860195865151610b8a8161086b565b905f5b818110610dc4575050610be86106eb9160406020860151950151906020850195610bb78751610f16565b6020815191012090610bc7610162565b938452602084015260408301526060820152604051928391602083016108ca565b606060018060a01b037f000000000000000000000000000000000000000000000000000000000000000016920151823b156100b85760405163020a49e360e51b8152925f92849283918291610c61917f000000000000000000000000000000000000000000000000000000000000000060048501610929565b03915afa8015610d9657610daa575b5085515195610c7e8761095f565b96732cb960d03080a42ac4d9d53c0cc87cd6795ec9b3915f5b828110610cd457505050506060815101515190825191825110610cbf575b5050505181529190565b606091604086015251015190525f8080610cb5565b610cdf8183516108b1565b5190610cee6020830151611196565b916020830190815115610d9b576060610d1b9460405180968192638b3e82b560e01b835260048301610a1e565b03818a5af4908115610d96576001945f92610d66575b50519151610d3d610173565b92835260208301526040820152610d54828d6108b1565b52610d5f818c6108b1565b5001610c97565b610d8891925060603d8111610d8f575b610d808183610141565b8101906109c7565b905f610d31565b503d610d76565b610954565b63b4eb9e5160e01b5f5260045ffd5b80610db85f610dbe93610141565b806104f7565b5f610c70565b806020610dd46001938d516108b1565b51015160208151910120610de882866108b1565b5201610b8d565b6040840190815151145f14610e045751610b79565b637202e68560e11b5f5260045ffd5b63beda4fc360e01b5f5260045ffd5b805191908290602001825e015f815290565b600461017191610e4f94936040519586926020840190610e22565b9063ffffffff60e01b16815203601b19810185520183610141565b9060405191602083015260208252610171604083610141565b600861017191610e9e94936040519586926020840190610e22565b906001600160401b0360c01b16815203601719810185520183610141565b6040516001600160e01b031990911660208201529190610171908390610ee6906024830190610e22565b03601f198101845283610141565b61017190610ee6610f1094936040519586936020850190610e22565b90610e22565b6107b490611094610f9882516040519060ff60f81b9060f81b16602082015260018152610f44602182610141565b610f92610f58602086015163ffffffff1690565b63ff00ff00600882811b9190911691901c62ff00ff1617601081811b63ffff00001691901c61ffff161760e01b6001600160e01b03191690565b90610e34565b611094608061108c610fad6040870151610e6a565b61108661105d6060890192611057610fcd8551516001600160401b031690565b67ffffffffffff000067ff00ff00ff00ff0066ff00ff00ff00ff8360081c169260081b169165ffff0000ffff65ffff0000ff0065ffffffffffff67ffff0000ffff0000861666ff0000ffff000085161760101c16941691161760101b161767ffffffff0000000063ffffffff8260201c169160201b166001600160401b0360c01b911760c01b1690565b90610e83565b91516110806040611078610f58602085015163ffffffff1690565b920151610e6a565b90610ebc565b94610ef4565b940151610e6a565b90610ef4565b604051906110a78261010b565b60606080835f81525f60208201525f60408201525f838201520152565b604051906110d1826100d0565b60606020835f81520152565b6040519061012082018281106001600160401b038211176100eb576040525f6101008382815261110b6110c4565b602082015282604082015261111e6110c4565b60608201528260808201526111316110c4565b60a08201528260c0820152606060e08201520152565b906111518261024a565b61115e6040519182610141565b828152809261116f601f199161024a565b01905f5b82811061117f57505050565b60209061118a6110dd565b82828501015201611173565b61119e61109a565b506111a7610182565b9081525f60208201526111c16111bc82611308565b6114db565b906111cb816115cb565b6111d76111bc83611308565b6111e36111bc84611308565b916111ed846115cb565b6111f681611147565b945f5b8281106112255750505061120b610191565b948552602085015260408401526060830152608082015290565b60019061123183611755565b60ff61123b6110dd565b9116806112675750600160c08201525b611255828a6108b1565b5261126081896108b1565b50016111f9565b6004810361128b575060016040820152611280846117d2565b60608201525b61124b565b600581036112ae5750600160808201526112a4846117d2565b60a082015261124b565b600681036112ce5750600181526112c4846117d2565b602082015261124b565b60080361128657600161010082015261124b565b634e487b7160e01b5f52601160045260245ffd5b9190820180921161130357565b6112e2565b6020810180516020810180911161130357825151106100b8576020915182825182010192839101116113035761133e6020610261565b9161134c6040519384610141565b6020835261135a6020610261565b6020840190601f19013682379060205b60208110156113b9578061139a57505f19905b811990511690825116179052611395602082516112f6565b905290565b6113ae6113a96113b39261193c565b6119cf565b61194a565b9061137d565b909182518152602081018091116113035791602081018091116113035790601f1981019081111561136a576112e2565b919060208301805182810180911161130357845151106100b85781156114c3576020935184825182010194859101116113035761142582610261565b916114336040519384610141565b80835261143f81610261565b602084019590601f19013687378195905b6020871015611494576113959394959680155f1461147f57505f19905b518251821691191617905282516112f6565b6113ae6113a961148e9261193c565b9061146d565b9081518152602081018091116113035790602081018091116113035795601f1981019081116113035795611450565b505090506040516114d5602082610141565b5f815290565b60208151106114eb576020015190565b60405162461bcd60e51b8152602060048201526024808201527f42797465733a3a20746f427974657333323a206461746120697320746f20736860448201526337b93a1760e11b6064820152608490fd5b60ff60049116019060ff821161130357565b1561155557565b60405162461bcd60e51b815260206004820152602860248201527f756e657870656374656420707265666978206465636f64696e6720436f6d706160448201526731ba1e2ab4b73a1f60c11b6064820152608490fd5b906001600160401b03809116911601906001600160401b03821161130357565b6115d481611755565b60038116806115f057506107b4915060021c603f165b60ff1690565b6001810361164157506116359061162f6115ea6116256116156115ea6107b497611755565b60061b67ffffffffffffffc01690565b9260021c603f1690565b906115ab565b6001600160401b031690565b600281036116c057506116b7906116aa60ff8461169b826116646107b498611755565b958161168a8161167c61167688611755565b97611755565b991660081b63ffffff001690565b911617921660101b63ffff00001690565b17921660181b63ff0000001690565b1760021c633fffffff1690565b63ffffffff1690565b6003036116ff576107b49160ff6116e66116e16116fa94603f9060021c1690565b61153c565b16906116f5600883111561154e565b6113e9565b611958565b60405162461bcd60e51b815260206004820152601a60248201527f436f64652073686f756c6420626520756e726561636861626c650000000000006044820152606490fd5b9081518110156108c5570160200190565b6020810190815160018101809111611303578151511061179e575181516001600160f81b0319916117869190611744565b511660f81c9080519060018201809211611303575290565b60405162461bcd60e51b815260206004820152600c60248201526b4f7574206f662072616e676560a01b6044820152606490fd5b6117da6110c4565b50602081019081516004810180911161130357815151106100b85760209181518382518201019384910111611303576118136004610261565b926118216040519485610141565b6004845261182f6004610261565b6020850190601f19013682379060045b602081101561190c57806118f757505f19905b81199051169082511617905261186a600482516112f6565b90525f915f905b600482106118b15750508061188861188e926115cb565b906113e9565b6118a9611899610182565b6001600160e01b03199093168352565b602082015290565b90926001600160f81b03196118c68584611744565b5116908460031b9185830460081486151715611303576001926001600160e01b0319918216901c1617930190611871565b6113ae6113a96119069261193c565b90611852565b909182518152602081018091116113035791602081018091116113035790601f1981019081111561183f576112e2565b602003906020821161130357565b5f1981019190821161130357565b80515f91815b61196757505090565b90915f1983018381116113035761197e8184611744565b5160f81c90600381901b906001600160fd1b038116036113035760ff8111611303576001901b90818102918183041490151715611303576119be916112f6565b918015611303575f1901908161195e565b601f8111611303576101000a9056fea264697066735822122016aa4d8047b1ad8f3df8cf9c0bc211c3e8c46005ba9e6d745f3404819a766f5a64736f6c634300081e003300000000000000000000000065b299f6d365f34a04b67f602b89f6fab094a01200468fb8911ecec00d7fd724627ea49172c901dfe0af8749b0af7a90c33e1948
Deployed Bytecode
0x60806040526004361015610011575f80fd5b5f3560e01c806301ffc9a71461006457806309a07dd31461005f5780631a2bd4871461005a5780637d7555981461005557638a17265114610050575f80fd5b61070c565b610604565b610501565b610425565b346100b85760203660031901126100b85760043563ffffffff60e01b81168091036100b857630faeaab360e31b81149081156100a7575b50151560805260206080f35b6301ffc9a760e01b1490508161009b565b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b038211176100eb57604052565b6100bc565b606081019081106001600160401b038211176100eb57604052565b60a081019081106001600160401b038211176100eb57604052565b608081019081106001600160401b038211176100eb57604052565b90601f801991011681019081106001600160401b038211176100eb57604052565b60405190610171608083610141565b565b60405190610171606083610141565b60405190610171604083610141565b6040519061017160a083610141565b91908260409103126100b8576040516101b8816100d0565b6020808294803584520135910152565b91908260609103126100b8576040516101e0816100f0565b604080829480358452602081013560208501520135910152565b91909160e0818403126100b857608060c0604051926102188461010b565b61023e8496823586526020830135602087015260408301356040870152606083016101c8565b60608501520135910152565b6001600160401b0381116100eb5760051b60200190565b6001600160401b0381116100eb57601f01601f191660200190565b81601f820112156100b85780359061029382610261565b926102a16040519485610141565b828452602083830101116100b857815f926020809301838601378301015290565b9080601f830112156100b8578135916102da8361024a565b926102e86040519485610141565b80845260208085019160051b830101918383116100b85760208101915b83831061031457505050505090565b82356001600160401b0381116100b8578201906040828703601f1901126100b85760405190610342826100d0565b602083013582526040830135916001600160401b0383116100b85761036f8860208096958196010161027c565b83820152815201920191610305565b91906080838203126100b85760405161039681610126565b80938035825260208101356020830152604081013560408301526060810135906001600160401b0382116100b857019180601f840112156100b85782356103dc8161024a565b936103ea6040519586610141565b81855260208086019260051b8201019283116100b857602001905b8282106104155750505060600152565b8135815260209182019101610405565b346100b85760403660031901126100b8576004356001600160401b0381116100b85761016060031982360301126100b8576040519061046382610126565b61047036826004016101a0565b825261047f36604483016101fa565b60208301526101248101356001600160401b0381116100b8576104a890600436918401016102c2565b60408301526101448101356001600160401b0381116100b85760609160046104d3923692010161027c565b9101526024356001600160401b0381116100b8576104f590369060040161037e565b005b5f9103126100b857565b346100b8575f3660031901126100b85760206040517f00468fb8911ecec00d7fd724627ea49172c901dfe0af8749b0af7a90c33e19488152f35b9181601f840112156100b8578235916001600160401b0383116100b857602083818601950101116100b857565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b9061059f90604083526040830190610568565b906020818303910152602080835192838152019201905f5b8181106105c45750505090565b909192602060a0600192604080885180518452858101518685015201518051828401528481015160608401520151608082015201940191019190916105b7565b346100b85760403660031901126100b8576004356001600160401b0381116100b85761063490369060040161053b565b6024356001600160401b0381116100b85761065390369060040161053b565b9091830192610100818503126100b8576106b76106eb936106da936106aa6106f99760a06040519661068488610126565b803588526020810135602089015261069f83604083016101c8565b6040890152016101c8565b6060850152810190610750565b916106c3949394610162565b948552602085015260408401526060830152610b3f565b9290604051928391602083016107b7565b03601f198101835282610141565b6107086040519283928361058c565b0390f35b346100b8575f3660031901126100b8576040517f00000000000000000000000065b299f6d365f34a04b67f602b89f6fab094a0126001600160a01b03168152602090f35b90610160828203126100b85761076681836101a0565b9261077482604085016101fa565b926101208101356001600160401b0381116100b857836107959183016102c2565b926101408201356001600160401b0381116100b8576107b4920161027c565b90565b6101719092919260a0606061010083019580518452602081015160208501526107fc604082015160408601906040809180518452602081015160208501520151910152565b01519101906040809180518452602081015160208501520151910152565b60405190610827826100f0565b5f6040838281528260208201520152565b6040519061084582610126565b815f81525f602082015261085761081a565b6040820152606061086661081a565b910152565b906108758261024a565b6108826040519182610141565b8281528092610893601f199161024a565b0190602036910137565b634e487b7160e01b5f52603260045260245ffd5b80518210156108c55760209160051b010190565b61089d565b9060208252602060c0606060a08501938051848701528381015160408701526040810151828701520151936080808201528451809452019201905f5b8181106109135750505090565b8251845260209384019390920191600101610906565b91610946906107b494928452606060208501526060840190610568565b916040818403910152610568565b6040513d5f823e3d90fd5b906109698261024a565b6109766040519182610141565b8281528092610987601f199161024a565b01905f5b82811061099757505050565b6020906040516109a6816100f0565b5f81525f838201526109b661081a565b60408201528282850101520161098b565b908160609103126100b85760408051916109e0836100f0565b80518352602081015160208401520151604082015290565b90604060206107b49363ffffffff60e01b81511684520151918160208201520190610568565b60208152608060c082019280516020840152602081015160408401526040810151606084015260608101518284015201519160a080830152825180915260e0820191602060e08360051b8301019401925f915b838310610a8057505050505090565b909192939460208060019260df19858203018652610b30895191610aa681845115159052565b61010080610b26610b08610aea610acc898901516101208b8901526101208801906109f8565b604089810151151590880152606089015187820360608901526109f8565b60808881015115159087015260a088015186820360a08801526109f8565b60c08781015115159086015260e087015185820360e0870152610568565b9401511515910152565b97019301930191939290610a71565b919091610b4a610838565b508251815181511115610e1357610b5f61081a565b506020810151606083019081515181145f14610def575080515b6040860195865151610b8a8161086b565b905f5b818110610dc4575050610be86106eb9160406020860151950151906020850195610bb78751610f16565b6020815191012090610bc7610162565b938452602084015260408301526060820152604051928391602083016108ca565b606060018060a01b037f00000000000000000000000065b299f6d365f34a04b67f602b89f6fab094a01216920151823b156100b85760405163020a49e360e51b8152925f92849283918291610c61917f00468fb8911ecec00d7fd724627ea49172c901dfe0af8749b0af7a90c33e194860048501610929565b03915afa8015610d9657610daa575b5085515195610c7e8761095f565b96732cb960d03080a42ac4d9d53c0cc87cd6795ec9b3915f5b828110610cd457505050506060815101515190825191825110610cbf575b5050505181529190565b606091604086015251015190525f8080610cb5565b610cdf8183516108b1565b5190610cee6020830151611196565b916020830190815115610d9b576060610d1b9460405180968192638b3e82b560e01b835260048301610a1e565b03818a5af4908115610d96576001945f92610d66575b50519151610d3d610173565b92835260208301526040820152610d54828d6108b1565b52610d5f818c6108b1565b5001610c97565b610d8891925060603d8111610d8f575b610d808183610141565b8101906109c7565b905f610d31565b503d610d76565b610954565b63b4eb9e5160e01b5f5260045ffd5b80610db85f610dbe93610141565b806104f7565b5f610c70565b806020610dd46001938d516108b1565b51015160208151910120610de882866108b1565b5201610b8d565b6040840190815151145f14610e045751610b79565b637202e68560e11b5f5260045ffd5b63beda4fc360e01b5f5260045ffd5b805191908290602001825e015f815290565b600461017191610e4f94936040519586926020840190610e22565b9063ffffffff60e01b16815203601b19810185520183610141565b9060405191602083015260208252610171604083610141565b600861017191610e9e94936040519586926020840190610e22565b906001600160401b0360c01b16815203601719810185520183610141565b6040516001600160e01b031990911660208201529190610171908390610ee6906024830190610e22565b03601f198101845283610141565b61017190610ee6610f1094936040519586936020850190610e22565b90610e22565b6107b490611094610f9882516040519060ff60f81b9060f81b16602082015260018152610f44602182610141565b610f92610f58602086015163ffffffff1690565b63ff00ff00600882811b9190911691901c62ff00ff1617601081811b63ffff00001691901c61ffff161760e01b6001600160e01b03191690565b90610e34565b611094608061108c610fad6040870151610e6a565b61108661105d6060890192611057610fcd8551516001600160401b031690565b67ffffffffffff000067ff00ff00ff00ff0066ff00ff00ff00ff8360081c169260081b169165ffff0000ffff65ffff0000ff0065ffffffffffff67ffff0000ffff0000861666ff0000ffff000085161760101c16941691161760101b161767ffffffff0000000063ffffffff8260201c169160201b166001600160401b0360c01b911760c01b1690565b90610e83565b91516110806040611078610f58602085015163ffffffff1690565b920151610e6a565b90610ebc565b94610ef4565b940151610e6a565b90610ef4565b604051906110a78261010b565b60606080835f81525f60208201525f60408201525f838201520152565b604051906110d1826100d0565b60606020835f81520152565b6040519061012082018281106001600160401b038211176100eb576040525f6101008382815261110b6110c4565b602082015282604082015261111e6110c4565b60608201528260808201526111316110c4565b60a08201528260c0820152606060e08201520152565b906111518261024a565b61115e6040519182610141565b828152809261116f601f199161024a565b01905f5b82811061117f57505050565b60209061118a6110dd565b82828501015201611173565b61119e61109a565b506111a7610182565b9081525f60208201526111c16111bc82611308565b6114db565b906111cb816115cb565b6111d76111bc83611308565b6111e36111bc84611308565b916111ed846115cb565b6111f681611147565b945f5b8281106112255750505061120b610191565b948552602085015260408401526060830152608082015290565b60019061123183611755565b60ff61123b6110dd565b9116806112675750600160c08201525b611255828a6108b1565b5261126081896108b1565b50016111f9565b6004810361128b575060016040820152611280846117d2565b60608201525b61124b565b600581036112ae5750600160808201526112a4846117d2565b60a082015261124b565b600681036112ce5750600181526112c4846117d2565b602082015261124b565b60080361128657600161010082015261124b565b634e487b7160e01b5f52601160045260245ffd5b9190820180921161130357565b6112e2565b6020810180516020810180911161130357825151106100b8576020915182825182010192839101116113035761133e6020610261565b9161134c6040519384610141565b6020835261135a6020610261565b6020840190601f19013682379060205b60208110156113b9578061139a57505f19905b811990511690825116179052611395602082516112f6565b905290565b6113ae6113a96113b39261193c565b6119cf565b61194a565b9061137d565b909182518152602081018091116113035791602081018091116113035790601f1981019081111561136a576112e2565b919060208301805182810180911161130357845151106100b85781156114c3576020935184825182010194859101116113035761142582610261565b916114336040519384610141565b80835261143f81610261565b602084019590601f19013687378195905b6020871015611494576113959394959680155f1461147f57505f19905b518251821691191617905282516112f6565b6113ae6113a961148e9261193c565b9061146d565b9081518152602081018091116113035790602081018091116113035795601f1981019081116113035795611450565b505090506040516114d5602082610141565b5f815290565b60208151106114eb576020015190565b60405162461bcd60e51b8152602060048201526024808201527f42797465733a3a20746f427974657333323a206461746120697320746f20736860448201526337b93a1760e11b6064820152608490fd5b60ff60049116019060ff821161130357565b1561155557565b60405162461bcd60e51b815260206004820152602860248201527f756e657870656374656420707265666978206465636f64696e6720436f6d706160448201526731ba1e2ab4b73a1f60c11b6064820152608490fd5b906001600160401b03809116911601906001600160401b03821161130357565b6115d481611755565b60038116806115f057506107b4915060021c603f165b60ff1690565b6001810361164157506116359061162f6115ea6116256116156115ea6107b497611755565b60061b67ffffffffffffffc01690565b9260021c603f1690565b906115ab565b6001600160401b031690565b600281036116c057506116b7906116aa60ff8461169b826116646107b498611755565b958161168a8161167c61167688611755565b97611755565b991660081b63ffffff001690565b911617921660101b63ffff00001690565b17921660181b63ff0000001690565b1760021c633fffffff1690565b63ffffffff1690565b6003036116ff576107b49160ff6116e66116e16116fa94603f9060021c1690565b61153c565b16906116f5600883111561154e565b6113e9565b611958565b60405162461bcd60e51b815260206004820152601a60248201527f436f64652073686f756c6420626520756e726561636861626c650000000000006044820152606490fd5b9081518110156108c5570160200190565b6020810190815160018101809111611303578151511061179e575181516001600160f81b0319916117869190611744565b511660f81c9080519060018201809211611303575290565b60405162461bcd60e51b815260206004820152600c60248201526b4f7574206f662072616e676560a01b6044820152606490fd5b6117da6110c4565b50602081019081516004810180911161130357815151106100b85760209181518382518201019384910111611303576118136004610261565b926118216040519485610141565b6004845261182f6004610261565b6020850190601f19013682379060045b602081101561190c57806118f757505f19905b81199051169082511617905261186a600482516112f6565b90525f915f905b600482106118b15750508061188861188e926115cb565b906113e9565b6118a9611899610182565b6001600160e01b03199093168352565b602082015290565b90926001600160f81b03196118c68584611744565b5116908460031b9185830460081486151715611303576001926001600160e01b0319918216901c1617930190611871565b6113ae6113a96119069261193c565b90611852565b909182518152602081018091116113035791602081018091116113035790601f1981019081111561183f576112e2565b602003906020821161130357565b5f1981019190821161130357565b80515f91815b61196757505090565b90915f1983018381116113035761197e8184611744565b5160f81c90600381901b906001600160fd1b038116036113035760ff8111611303576001901b90818102918183041490151715611303576119be916112f6565b918015611303575f1901908161195e565b601f8111611303576101000a9056fea264697066735822122016aa4d8047b1ad8f3df8cf9c0bc211c3e8c46005ba9e6d745f3404819a766f5a64736f6c634300081e0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000065b299f6d365f34a04b67f602b89f6fab094a01200468fb8911ecec00d7fd724627ea49172c901dfe0af8749b0af7a90c33e1948
-----Decoded View---------------
Arg [0] : verifier (address): 0x65B299f6d365F34a04B67f602B89f6Fab094a012
Arg [1] : verificationKey (bytes32): 0x00468fb8911ecec00d7fd724627ea49172c901dfe0af8749b0af7a90c33e1948
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 00000000000000000000000065b299f6d365f34a04b67f602b89f6fab094a012
Arg [1] : 00468fb8911ecec00d7fd724627ea49172c901dfe0af8749b0af7a90c33e1948
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.