Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
Latest 25 from a total of 5,993 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Submit Final | 7079060 | 89 days ago | IN | 0 ETH | 0.00000096 | ||||
Commit Prev Rand... | 7079058 | 89 days ago | IN | 0 ETH | 0.00000009 | ||||
Submit Initial | 7078928 | 89 days ago | IN | 0 ETH | 0.00000026 | ||||
Submit Final | 7078782 | 89 days ago | IN | 0 ETH | 0.00000093 | ||||
Commit Prev Rand... | 7078780 | 89 days ago | IN | 0 ETH | 0.00000008 | ||||
Submit Initial | 7078650 | 89 days ago | IN | 0 ETH | 0.00000019 | ||||
Submit Final | 7078503 | 89 days ago | IN | 0 ETH | 0.00000069 | ||||
Commit Prev Rand... | 7078501 | 89 days ago | IN | 0 ETH | 0.00000006 | ||||
Submit Initial | 7078369 | 89 days ago | IN | 0 ETH | 0.00000024 | ||||
Submit Final | 7078216 | 89 days ago | IN | 0 ETH | 0.00000096 | ||||
Commit Prev Rand... | 7078214 | 89 days ago | IN | 0 ETH | 0.00000009 | ||||
Submit Initial | 7078084 | 89 days ago | IN | 0 ETH | 0.00000255 | ||||
Submit Final | 7077938 | 89 days ago | IN | 0 ETH | 0.00000227 | ||||
Commit Prev Rand... | 7077936 | 89 days ago | IN | 0 ETH | 0.00000021 | ||||
Submit Initial | 7077806 | 89 days ago | IN | 0 ETH | 0.00000146 | ||||
Submit Final | 7077648 | 89 days ago | IN | 0 ETH | 0.0000298 | ||||
Commit Prev Rand... | 7077646 | 89 days ago | IN | 0 ETH | 0.00000273 | ||||
Submit Initial | 7077516 | 89 days ago | IN | 0 ETH | 0.00002314 | ||||
Submit Final | 7077362 | 89 days ago | IN | 0 ETH | 0.00008123 | ||||
Commit Prev Rand... | 7077360 | 89 days ago | IN | 0 ETH | 0.00000796 | ||||
Submit Initial | 7077230 | 89 days ago | IN | 0 ETH | 0.00003725 | ||||
Submit Final | 7077075 | 89 days ago | IN | 0 ETH | 0.00019958 | ||||
Commit Prev Rand... | 7077073 | 89 days ago | IN | 0 ETH | 0.00002039 | ||||
Submit Initial | 7076943 | 89 days ago | IN | 0 ETH | 0.00007875 | ||||
Submit Final | 7076788 | 89 days ago | IN | 0 ETH | 0.00051041 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
BeefyClient
Compiler Version
v0.8.25+commit.b61c2a91
Optimization Enabled:
Yes with 20000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: 2023 Snowfork <[email protected]> pragma solidity 0.8.25; import {ECDSA} from "openzeppelin/utils/cryptography/ECDSA.sol"; import {SubstrateMerkleProof} from "./utils/SubstrateMerkleProof.sol"; import {Bitfield} from "./utils/Bitfield.sol"; import {Uint16Array, createUint16Array} from "./utils/Uint16Array.sol"; import {Math} from "./utils/Math.sol"; import {MMRProof} from "./utils/MMRProof.sol"; import {ScaleCodec} from "./utils/ScaleCodec.sol"; /** * @title BeefyClient * * High-level documentation at https://docs.snowbridge.network/architecture/verification/polkadot * * To submit new commitments, relayers must call the following methods sequentially: * 1. submitInitial: Setup the session for the interactive submission * 2. commitPrevRandao: Commit to a random seed for generating a validator subsampling * 3. createFinalBitfield: Generate the validator subsampling * 4. submitFinal: Complete submission after providing the request validator signatures * */ contract BeefyClient { using Math for uint16; using Math for uint256; /* Events */ /** * @dev Emitted when the MMR root is updated * @param mmrRoot the updated MMR root * @param blockNumber the beefy block number of the updated MMR root */ event NewMMRRoot(bytes32 mmrRoot, uint64 blockNumber); /** * @dev Emitted when a new ticket has been created * @param relayer The relayer who created the ticket * @param blockNumber the parent block number of the candidate MMR root */ event NewTicket(address relayer, uint64 blockNumber); /* Types */ /** * @dev The Commitment, with its payload, is the core thing we are trying to verify with * this contract. It contains an MMR root that commits to the polkadot history, including * past blocks and parachain blocks and can be used to verify both polkadot and parachain blocks. */ struct Commitment { // Relay chain block number uint32 blockNumber; // ID of the validator set that signed the commitment uint64 validatorSetID; // The payload of the new commitment in beefy justifications (in // our case, this is a new MMR root for all past polkadot blocks) PayloadItem[] payload; } /** * @dev Each PayloadItem is a piece of data signed by validators at a particular block. */ struct PayloadItem { // An ID that references a description of the data in the payload item. // Known payload ids can be found [upstream](https://github.com/paritytech/substrate/blob/fe1f8ba1c4f23931ae89c1ada35efb3d908b50f5/primitives/consensus/beefy/src/payload.rs#L27). bytes2 payloadID; // The contents of the payload item bytes data; } /** * @dev The ValidatorProof is a proof used to verify a commitment signature */ struct ValidatorProof { // The parity bit to specify the intended solution uint8 v; // The x component on the secp256k1 curve bytes32 r; // The challenge solution bytes32 s; // Leaf index of the validator address in the merkle tree uint256 index; // Validator address address account; // Merkle proof for the validator bytes32[] proof; } /** * @dev A ticket tracks working state for the interactive submission of new commitments */ struct Ticket { // The block number this ticket was issued uint64 blockNumber; // Length of the validator set that signed the commitment uint32 validatorSetLen; // The number of signatures required uint32 numRequiredSignatures; // The PREVRANDAO seed selected for this ticket session uint256 prevRandao; // Hash of a bitfield claiming which validators have signed bytes32 bitfieldHash; } /// @dev The MMRLeaf describes the leaf structure of the MMR struct MMRLeaf { // Version of the leaf type uint8 version; // Parent number of the block this leaf describes uint32 parentNumber; // Parent hash of the block this leaf describes bytes32 parentHash; // Validator set id that will be part of consensus for the next block uint64 nextAuthoritySetID; // Length of that validator set uint32 nextAuthoritySetLen; // Merkle root of all public keys in that validator set bytes32 nextAuthoritySetRoot; // Merkle root of all parachain headers in this block bytes32 parachainHeadsRoot; } /** * @dev The ValidatorSet describes a BEEFY validator set */ struct ValidatorSet { // Identifier for the set uint128 id; // Number of validators in the set uint128 length; // Merkle root of BEEFY validator addresses bytes32 root; } /** * @dev The ValidatorSetState describes a BEEFY validator set along with signature usage counters */ struct ValidatorSetState { // Identifier for the set uint128 id; // Number of validators in the set uint128 length; // Merkle root of BEEFY validator addresses bytes32 root; // Number of times a validator signature has been used Uint16Array usageCounters; } /* State */ /// @dev The latest verified MMR root bytes32 public latestMMRRoot; /// @dev The block number in the relay chain in which the latest MMR root was emitted uint64 public latestBeefyBlock; /// @dev State of the current validator set ValidatorSetState public currentValidatorSet; /// @dev State of the next validator set ValidatorSetState public nextValidatorSet; /// @dev Pending tickets for commitment submission mapping(bytes32 ticketID => Ticket) public tickets; /* Constants */ /** * @dev Beefy payload id for MMR Root payload items: * https://github.com/paritytech/substrate/blob/fe1f8ba1c4f23931ae89c1ada35efb3d908b50f5/primitives/consensus/beefy/src/payload.rs#L33 */ bytes2 public constant MMR_ROOT_ID = bytes2("mh"); /** * @dev Minimum delay in number of blocks that a relayer must wait between calling * submitInitial and commitPrevRandao. In production this should be set to MAX_SEED_LOOKAHEAD: * https://eth2book.info/altair/part3/config/preset#max_seed_lookahead */ uint256 public immutable randaoCommitDelay; /** * @dev after randaoCommitDelay is reached, relayer must * call commitPrevRandao within this number of blocks. * Without this expiration, relayers can roll the dice infinitely to get the subsampling * they desire. */ uint256 public immutable randaoCommitExpiration; /** * @dev Minimum number of signatures required to validate a new commitment. This parameter * is calculated based on `randaoCommitExpiration`. See ~/scripts/beefy_signature_sampling.py * for the calculation. */ uint256 public immutable minNumRequiredSignatures; /* Errors */ error InvalidBitfield(); error InvalidBitfieldLength(); error InvalidCommitment(); error InvalidMMRLeaf(); error InvalidMMRLeafProof(); error InvalidMMRRootLength(); error InvalidSignature(); error InvalidTicket(); error InvalidValidatorProof(); error InvalidValidatorProofLength(); error CommitmentNotRelevant(); error NotEnoughClaims(); error PrevRandaoAlreadyCaptured(); error PrevRandaoNotCaptured(); error StaleCommitment(); error TicketExpired(); error WaitPeriodNotOver(); constructor( uint256 _randaoCommitDelay, uint256 _randaoCommitExpiration, uint256 _minNumRequiredSignatures, uint64 _initialBeefyBlock, ValidatorSet memory _initialValidatorSet, ValidatorSet memory _nextValidatorSet ) { if (_nextValidatorSet.id != _initialValidatorSet.id + 1) { revert("invalid-constructor-params"); } randaoCommitDelay = _randaoCommitDelay; randaoCommitExpiration = _randaoCommitExpiration; minNumRequiredSignatures = _minNumRequiredSignatures; latestBeefyBlock = _initialBeefyBlock; currentValidatorSet.id = _initialValidatorSet.id; currentValidatorSet.length = _initialValidatorSet.length; currentValidatorSet.root = _initialValidatorSet.root; currentValidatorSet.usageCounters = createUint16Array(currentValidatorSet.length); nextValidatorSet.id = _nextValidatorSet.id; nextValidatorSet.length = _nextValidatorSet.length; nextValidatorSet.root = _nextValidatorSet.root; nextValidatorSet.usageCounters = createUint16Array(nextValidatorSet.length); } /* External Functions */ /** * @dev Begin submission of commitment * @param commitment contains the commitment signed by the validators * @param bitfield a bitfield claiming which validators have signed the commitment * @param proof a proof that a single validator from currentValidatorSet has signed the commitment */ function submitInitial(Commitment calldata commitment, uint256[] calldata bitfield, ValidatorProof calldata proof) external { if (commitment.blockNumber <= latestBeefyBlock) { revert StaleCommitment(); } ValidatorSetState storage vset; uint16 signatureUsageCount; if (commitment.validatorSetID == currentValidatorSet.id) { signatureUsageCount = currentValidatorSet.usageCounters.get(proof.index); currentValidatorSet.usageCounters.set(proof.index, signatureUsageCount.saturatingAdd(1)); vset = currentValidatorSet; } else if (commitment.validatorSetID == nextValidatorSet.id) { signatureUsageCount = nextValidatorSet.usageCounters.get(proof.index); nextValidatorSet.usageCounters.set(proof.index, signatureUsageCount.saturatingAdd(1)); vset = nextValidatorSet; } else { revert InvalidCommitment(); } // Check if merkle proof is valid based on the validatorSetRoot and if proof is included in bitfield if (!isValidatorInSet(vset, proof.account, proof.index, proof.proof) || !Bitfield.isSet(bitfield, proof.index)) { revert InvalidValidatorProof(); } // Check if validatorSignature is correct, ie. check if it matches // the signature of senderPublicKey on the commitmentHash bytes32 commitmentHash = keccak256(encodeCommitment(commitment)); if (ECDSA.recover(commitmentHash, proof.v, proof.r, proof.s) != proof.account) { revert InvalidSignature(); } // For the initial submission, the supplied bitfield should claim that more than // two thirds of the validator set have sign the commitment if (Bitfield.countSetBits(bitfield) < computeQuorum(vset.length)) { revert NotEnoughClaims(); } tickets[createTicketID(msg.sender, commitmentHash)] = Ticket({ blockNumber: uint64(block.number), validatorSetLen: uint32(vset.length), numRequiredSignatures: uint32( computeNumRequiredSignatures(vset.length, signatureUsageCount, minNumRequiredSignatures) ), prevRandao: 0, bitfieldHash: keccak256(abi.encodePacked(bitfield)) }); emit NewTicket(msg.sender, commitment.blockNumber); } /** * @dev Capture PREVRANDAO * @param commitmentHash contains the commitmentHash signed by the validators */ function commitPrevRandao(bytes32 commitmentHash) external { bytes32 ticketID = createTicketID(msg.sender, commitmentHash); Ticket storage ticket = tickets[ticketID]; if (ticket.blockNumber == 0) { revert InvalidTicket(); } if (ticket.prevRandao != 0) { revert PrevRandaoAlreadyCaptured(); } // relayer must wait `randaoCommitDelay` blocks if (block.number < ticket.blockNumber + randaoCommitDelay) { revert WaitPeriodNotOver(); } // relayer can capture within `randaoCommitExpiration` blocks if (block.number > ticket.blockNumber + randaoCommitDelay + randaoCommitExpiration) { delete tickets[ticketID]; revert TicketExpired(); } // Post-merge, the difficulty opcode now returns PREVRANDAO ticket.prevRandao = block.prevrandao; } /** * @dev Submit a commitment and leaf for final verification * @param commitment contains the full commitment that was used for the commitmentHash * @param bitfield claiming which validators have signed the commitment * @param proofs a struct containing the data needed to verify all validator signatures * @param leaf an MMR leaf provable using the MMR root in the commitment payload * @param leafProof an MMR leaf proof * @param leafProofOrder a bitfield describing the order of each item (left vs right) */ function submitFinal( Commitment calldata commitment, uint256[] calldata bitfield, ValidatorProof[] calldata proofs, MMRLeaf calldata leaf, bytes32[] calldata leafProof, uint256 leafProofOrder ) external { bytes32 commitmentHash = keccak256(encodeCommitment(commitment)); bytes32 ticketID = createTicketID(msg.sender, commitmentHash); validateTicket(ticketID, commitment, bitfield); bool is_next_session = false; ValidatorSetState storage vset; if (commitment.validatorSetID == nextValidatorSet.id) { is_next_session = true; vset = nextValidatorSet; } else if (commitment.validatorSetID == currentValidatorSet.id) { vset = currentValidatorSet; } else { revert InvalidCommitment(); } verifyCommitment(commitmentHash, ticketID, bitfield, vset, proofs); bytes32 newMMRRoot = ensureProvidesMMRRoot(commitment); if (is_next_session) { if (leaf.nextAuthoritySetID != nextValidatorSet.id + 1) { revert InvalidMMRLeaf(); } bool leafIsValid = MMRProof.verifyLeafProof(newMMRRoot, keccak256(encodeMMRLeaf(leaf)), leafProof, leafProofOrder); if (!leafIsValid) { revert InvalidMMRLeafProof(); } currentValidatorSet = nextValidatorSet; nextValidatorSet.id = leaf.nextAuthoritySetID; nextValidatorSet.length = leaf.nextAuthoritySetLen; nextValidatorSet.root = leaf.nextAuthoritySetRoot; nextValidatorSet.usageCounters = createUint16Array(leaf.nextAuthoritySetLen); } latestMMRRoot = newMMRRoot; latestBeefyBlock = commitment.blockNumber; delete tickets[ticketID]; emit NewMMRRoot(newMMRRoot, commitment.blockNumber); } /** * @dev Verify that the supplied MMR leaf is included in the latest verified MMR root. * @param leafHash contains the merkle leaf to be verified * @param proof contains simplified mmr proof * @param proofOrder a bitfield describing the order of each item (left vs right) */ function verifyMMRLeafProof(bytes32 leafHash, bytes32[] calldata proof, uint256 proofOrder) external view returns (bool) { return MMRProof.verifyLeafProof(latestMMRRoot, leafHash, proof, proofOrder); } /** * @dev Helper to create an initial validator bitfield. * @param bitsToSet contains indexes of all signed validators, should be deduplicated * @param length of validator set */ function createInitialBitfield(uint256[] calldata bitsToSet, uint256 length) external pure returns (uint256[] memory) { if (length < bitsToSet.length) { revert InvalidBitfieldLength(); } return Bitfield.createBitfield(bitsToSet, length); } /** * @dev Helper to create a final bitfield, with subsampled validator selections * @param commitmentHash contains the commitmentHash signed by the validators * @param bitfield claiming which validators have signed the commitment */ function createFinalBitfield(bytes32 commitmentHash, uint256[] calldata bitfield) external view returns (uint256[] memory) { Ticket storage ticket = tickets[createTicketID(msg.sender, commitmentHash)]; if (ticket.bitfieldHash != keccak256(abi.encodePacked(bitfield))) { revert InvalidBitfield(); } return Bitfield.subsample(ticket.prevRandao, bitfield, ticket.numRequiredSignatures, ticket.validatorSetLen); } /* Internal Functions */ // Creates a unique ticket ID for a new interactive prover-verifier session function createTicketID(address account, bytes32 commitmentHash) internal pure returns (bytes32 value) { assembly { mstore(0x00, account) mstore(0x20, commitmentHash) value := keccak256(0x0, 0x40) } } /** * @dev Calculates the number of required signatures for `submitFinal`. * @param validatorSetLen The length of the validator set * @param signatureUsageCount A counter of the number of times the validator signature was previously used in a call to `submitInitial` within the session. * @param minRequiredSignatures The minimum amount of signatures to verify */ // For more details on the calculation, read the following: // 1. https://docs.snowbridge.network/architecture/verification/polkadot#signature-sampling // 2. https://hackmd.io/9OedC7icR5m-in_moUZ_WQ function computeNumRequiredSignatures( uint256 validatorSetLen, uint256 signatureUsageCount, uint256 minRequiredSignatures ) internal pure returns (uint256) { // Start with the minimum number of signatures. uint256 numRequiredSignatures = minRequiredSignatures; // Add signatures based on the number of validators in the validator set. numRequiredSignatures += Math.log2(validatorSetLen, Math.Rounding.Ceil); // Add signatures based on the signature usage count. numRequiredSignatures += 1 + (2 * Math.log2(signatureUsageCount, Math.Rounding.Ceil)); // Never require more signatures than a 2/3 majority return Math.min(numRequiredSignatures, computeQuorum(validatorSetLen)); } /** * @dev Calculates 2/3 majority required for quorum for a given number of validators. * @param numValidators The number of validators in the validator set. */ function computeQuorum(uint256 numValidators) internal pure returns (uint256) { return numValidators - (numValidators - 1) / 3; } /** * @dev Verify commitment using the supplied signature proofs */ function verifyCommitment( bytes32 commitmentHash, bytes32 ticketID, uint256[] calldata bitfield, ValidatorSetState storage vset, ValidatorProof[] calldata proofs ) internal view { Ticket storage ticket = tickets[ticketID]; // Verify that enough signature proofs have been supplied uint256 numRequiredSignatures = ticket.numRequiredSignatures; if (proofs.length != numRequiredSignatures) { revert InvalidValidatorProofLength(); } // Generate final bitfield indicating which validators need to be included in the proofs. uint256[] memory finalbitfield = Bitfield.subsample(ticket.prevRandao, bitfield, numRequiredSignatures, vset.length); for (uint256 i = 0; i < proofs.length; i++) { ValidatorProof calldata proof = proofs[i]; // Check that validator is in bitfield if (!Bitfield.isSet(finalbitfield, proof.index)) { revert InvalidValidatorProof(); } // Check that validator is actually in a validator set if (!isValidatorInSet(vset, proof.account, proof.index, proof.proof)) { revert InvalidValidatorProof(); } // Check that validator signed the commitment if (ECDSA.recover(commitmentHash, proof.v, proof.r, proof.s) != proof.account) { revert InvalidSignature(); } // Ensure no validator can appear more than once in bitfield Bitfield.unset(finalbitfield, proof.index); } } // Ensure that the commitment provides a new MMR root function ensureProvidesMMRRoot(Commitment calldata commitment) internal pure returns (bytes32) { for (uint256 i = 0; i < commitment.payload.length; i++) { if (commitment.payload[i].payloadID == MMR_ROOT_ID) { if (commitment.payload[i].data.length != 32) { revert InvalidMMRRootLength(); } else { return bytes32(commitment.payload[i].data); } } } revert CommitmentNotRelevant(); } function encodeCommitment(Commitment calldata commitment) internal pure returns (bytes memory) { return bytes.concat( encodeCommitmentPayload(commitment.payload), ScaleCodec.encodeU32(commitment.blockNumber), ScaleCodec.encodeU64(commitment.validatorSetID) ); } function encodeCommitmentPayload(PayloadItem[] calldata items) internal pure returns (bytes memory) { bytes memory payload = ScaleCodec.checkedEncodeCompactU32(items.length); for (uint256 i = 0; i < items.length; i++) { payload = bytes.concat( payload, items[i].payloadID, ScaleCodec.checkedEncodeCompactU32(items[i].data.length), items[i].data ); } return payload; } function encodeMMRLeaf(MMRLeaf calldata leaf) internal pure returns (bytes memory) { return bytes.concat( ScaleCodec.encodeU8(leaf.version), ScaleCodec.encodeU32(leaf.parentNumber), leaf.parentHash, ScaleCodec.encodeU64(leaf.nextAuthoritySetID), ScaleCodec.encodeU32(leaf.nextAuthoritySetLen), leaf.nextAuthoritySetRoot, leaf.parachainHeadsRoot ); } /** * @dev Checks if a validators address is a member of the merkle tree * @param vset The validator set * @param account The address of the validator to check for inclusion in `vset`. * @param index The leaf index of the account in the merkle tree of validator set addresses. * @param proof Merkle proof required for validation of the address * @return true if the validator is in the set */ function isValidatorInSet(ValidatorSetState storage vset, address account, uint256 index, bytes32[] calldata proof) internal view returns (bool) { bytes32 hashedLeaf = keccak256(abi.encodePacked(account)); return SubstrateMerkleProof.verify(vset.root, hashedLeaf, index, vset.length, proof); } /** * @dev Basic validation of a ticket for submitFinal */ function validateTicket(bytes32 ticketID, Commitment calldata commitment, uint256[] calldata bitfield) internal view { Ticket storage ticket = tickets[ticketID]; if (ticket.blockNumber == 0) { // submitInitial hasn't been called yet revert InvalidTicket(); } if (ticket.prevRandao == 0) { // commitPrevRandao hasn't been called yet revert PrevRandaoNotCaptured(); } if (commitment.blockNumber <= latestBeefyBlock) { // ticket is obsolete revert StaleCommitment(); } if (ticket.bitfieldHash != keccak256(abi.encodePacked(bitfield))) { // The provided claims bitfield isn't the same one that was // passed to submitInitial revert InvalidBitfield(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/ECDSA.sol) pragma solidity ^0.8.0; import "../Strings.sol"; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS, InvalidSignatureV // Deprecated in v4.8 } function _throwError(RecoverError error) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert("ECDSA: invalid signature"); } else if (error == RecoverError.InvalidSignatureLength) { revert("ECDSA: invalid signature length"); } else if (error == RecoverError.InvalidSignatureS) { revert("ECDSA: invalid signature 's' value"); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature` or error string. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) { if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. /// @solidity memory-safe-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else { return (address(0), RecoverError.InvalidSignatureLength); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, signature); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError) { bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); uint8 v = uint8((uint256(vs) >> 255) + 27); return tryRecover(hash, v, r, s); } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. * * _Available since v4.2._ */ function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, r, vs); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. * * _Available since v4.3._ */ function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address, RecoverError) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return (address(0), RecoverError.InvalidSignatureS); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { return (address(0), RecoverError.InvalidSignature); } return (signer, RecoverError.NoError); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, v, r, s); _throwError(error); return recovered; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 message) { // 32 is the length in bytes of hash, // enforced by the type signature above /// @solidity memory-safe-assembly assembly { mstore(0x00, "\x19Ethereum Signed Message:\n32") mstore(0x1c, hash) message := keccak256(0x00, 0x3c) } } /** * @dev Returns an Ethereum Signed Message, created from `s`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s)); } /** * @dev Returns an Ethereum Signed Typed Data, created from a * `domainSeparator` and a `structHash`. This produces hash corresponding * to the one signed with the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] * JSON-RPC method as part of EIP-712. * * See {recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 data) { /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) mstore(ptr, "\x19\x01") mstore(add(ptr, 0x02), domainSeparator) mstore(add(ptr, 0x22), structHash) data := keccak256(ptr, 0x42) } } /** * @dev Returns an Ethereum Signed Data with intended validator, created from a * `validator` and `data` according to the version 0 of EIP-191. * * See {recover}. */ function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19\x00", validator, data)); } }
// SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: 2023 Snowfork <[email protected]> pragma solidity 0.8.25; // Used to verify merkle proofs generated by https://github.com/paritytech/substrate/tree/master/utils/binary-merkle-tree library SubstrateMerkleProof { /** * @notice Verify that a specific leaf element is part of the Merkle Tree at a specific position in the tree * * The tree would have been constructed using * https://paritytech.github.io/substrate/master/binary_merkle_tree/fn.merkle_root.html * * This implementation adapted from * https://paritytech.github.io/substrate/master/binary_merkle_tree/fn.verify_proof.html * * @param root the root of the merkle tree * @param leaf the leaf which needs to be proven * @param position the position of the leaf, index starting with 0 * @param width the width or number of leaves in the tree * @param proof the array of proofs to help verify the leaf's membership, ordered from leaf to root * @return a boolean value representing the success or failure of the operation */ function verify(bytes32 root, bytes32 leaf, uint256 position, uint256 width, bytes32[] calldata proof) internal pure returns (bool) { if (position >= width) { return false; } return root == computeRoot(leaf, position, width, proof); } function computeRoot(bytes32 leaf, uint256 position, uint256 width, bytes32[] calldata proof) internal pure returns (bytes32) { bytes32 node = leaf; unchecked { for (uint256 i = 0; i < proof.length; i++) { if (position & 1 == 1 || position + 1 == width) { node = efficientHash(proof[i], node); } else { node = efficientHash(node, proof[i]); } position = position >> 1; width = ((width - 1) >> 1) + 1; } return node; } } function efficientHash(bytes32 a, bytes32 b) internal pure returns (bytes32 value) { /// @solidity memory-safe-assembly assembly { mstore(0x00, a) mstore(0x20, b) value := keccak256(0x00, 0x40) } } }
// SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: 2023 Snowfork <[email protected]> pragma solidity 0.8.25; import {Bits} from "./Bits.sol"; library Bitfield { using Bits for uint256; /** * @dev Constants used to efficiently calculate the hamming weight of a bitfield. See * https://en.wikipedia.org/wiki/Hamming_weight#Efficient_implementation for an explanation of those constants. */ uint256 internal constant M1 = 0x5555555555555555555555555555555555555555555555555555555555555555; uint256 internal constant M2 = 0x3333333333333333333333333333333333333333333333333333333333333333; uint256 internal constant M4 = 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f; uint256 internal constant M8 = 0x00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff; uint256 internal constant M16 = 0x0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff; uint256 internal constant M32 = 0x00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffffff; uint256 internal constant M64 = 0x0000000000000000ffffffffffffffff0000000000000000ffffffffffffffff; uint256 internal constant M128 = 0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff; uint256 internal constant ONE = uint256(1); /** * @notice Core subsampling algorithm. Draws a random number, derives an index in the bitfield, and sets the bit if it is in the `prior` and not * yet set. Repeats that `n` times. * @param seed Source of randomness for selecting validator signatures. * @param prior Bitfield indicating which validators claim to have signed the commitment. * @param n Number of unique bits in prior that must be set in the result. Must be <= number of set bits in `prior`. * @param length Length of the bitfield prior to draw bits from. Must be <= prior.length * 256. */ function subsample(uint256 seed, uint256[] memory prior, uint256 n, uint256 length) internal pure returns (uint256[] memory bitfield) { bitfield = new uint256[](prior.length); uint256 found = 0; for (uint256 i = 0; found < n;) { uint256 index = makeIndex(seed, i, length); // require randomly selected bit to be set in prior and not yet set in bitfield if (!isSet(prior, index) || isSet(bitfield, index)) { unchecked { i++; } continue; } set(bitfield, index); unchecked { found++; i++; } } return bitfield; } /** * @dev Helper to create a bitfield. */ function createBitfield(uint256[] calldata bitsToSet, uint256 length) internal pure returns (uint256[] memory bitfield) { // Calculate length of uint256 array based on rounding up to number of uint256 needed uint256 arrayLength = (length + 255) / 256; bitfield = new uint256[](arrayLength); for (uint256 i = 0; i < bitsToSet.length; i++) { set(bitfield, bitsToSet[i]); } return bitfield; } /** * @notice Calculates the number of set bits by using the hamming weight of the bitfield. * The algorithm below is implemented after https://en.wikipedia.org/wiki/Hamming_weight#Efficient_implementation. * Further improvements are possible, see the article above. */ function countSetBits(uint256[] memory self) internal pure returns (uint256) { unchecked { uint256 count = 0; for (uint256 i = 0; i < self.length; i++) { uint256 x = self[i]; x = (x & M1) + ((x >> 1) & M1); //put count of each 2 bits into those 2 bits x = (x & M2) + ((x >> 2) & M2); //put count of each 4 bits into those 4 bits x = (x & M4) + ((x >> 4) & M4); //put count of each 8 bits into those 8 bits x = (x & M8) + ((x >> 8) & M8); //put count of each 16 bits into those 16 bits x = (x & M16) + ((x >> 16) & M16); //put count of each 32 bits into those 32 bits x = (x & M32) + ((x >> 32) & M32); //put count of each 64 bits into those 64 bits x = (x & M64) + ((x >> 64) & M64); //put count of each 128 bits into those 128 bits x = (x & M128) + ((x >> 128) & M128); //put count of each 256 bits into those 256 bits count += x; } return count; } } function isSet(uint256[] memory self, uint256 index) internal pure returns (bool) { uint256 element = index >> 8; return self[element].bit(uint8(index)) == 1; } function set(uint256[] memory self, uint256 index) internal pure { uint256 element = index >> 8; self[element] = self[element].setBit(uint8(index)); } function unset(uint256[] memory self, uint256 index) internal pure { uint256 element = index >> 8; self[element] = self[element].clearBit(uint8(index)); } function makeIndex(uint256 seed, uint256 iteration, uint256 length) internal pure returns (uint256 index) { assembly { mstore(0x00, seed) mstore(0x20, iteration) index := mod(keccak256(0x00, 0x40), length) } } }
// SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: 2023 Snowfork <[email protected]> pragma solidity 0.8.25; /** * @title A utility library for 16 bit counters packed in 256 bit array. * @dev The BeefyClient needs to store a count of how many times a validators signature is used. In solidity * a uint16 would take up as much space as a uin256 in storage, making storing counters for 1000 validators * expensive in terms of gas. The BeefyClient only needs 16 bits per counter. This library allows us to pack * 16 uint16 into a single uint256 and save 16x storage. * * Layout of 32 counters (2 uint256) * We store all counts in a single large uint256 array and convert from index from the logical uint16 array * to the physical uint256 array. * * 0 1 2 * uint256[] |-- -- -- -- -- -- -- -- -- -- -- -- YY -- -- --|-- -- -- -- -- -- XX -- -- -- -- -- -- -- -- --| * uint16[] |--|--|--|--|--|--|--|--|--|--|--|--|YY|--|--|--|--|--|--|--|--|--|XX|--|--|--|--|--|--|--|--|--| * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 * * Logical Index Layout * We use the first 4 * |-------...---------|----| * 256 4 0 * ^index ^bit-index * * In the above table counter YY is at logical index 12 in the uint16 array. It will convert to a physical * index of 0 in the physical uint256 array and then to bit-index of 192 to 207 of that uint256. In the * above table counter XX is at logical index 22. It will convert to a physical index of 1 in the array and * then to bit-index 96 to 111 of uint256[1]. */ using {get, set} for Uint16Array global; error IndexOutOfBounds(); /** * @dev stores the backing array and the length. */ struct Uint16Array { uint256[] data; uint256 length; } /** * @dev Creates a new counter which can store at least `length` counters. * @param length The amount of counters. */ function createUint16Array(uint256 length) pure returns (Uint16Array memory) { // create space for `length` elements and round up if needed. uint256 bufferLength = length / 16 + (length % 16 == 0 ? 0 : 1); return Uint16Array({data: new uint256[](bufferLength), length: length}); } /** * @dev Gets the counter at the logical index * @param self The array. * @param index The logical index. */ function get(Uint16Array storage self, uint256 index) view returns (uint16) { if (index >= self.length) { revert IndexOutOfBounds(); } // Right-shift the index by 4. This truncates the first 4 bits (bit-index) leaving us with the index // into the array. uint256 element = index >> 4; // Mask out the first 4 bits of the logical index to give us the bit-index. uint8 inside = uint8(index) & 0x0F; // find the element in the array, shift until its bit index and mask to only take the first 16 bits. return uint16((self.data[element] >> (16 * inside)) & 0xFFFF); } /** * @dev Sets the counter at the logical index. * @param self The array. * @param index The logical index of the counter in the array. * @param value The value to set the counter to. */ function set(Uint16Array storage self, uint256 index, uint16 value) { if (index >= self.length) { revert IndexOutOfBounds(); } // Right-shift the index by 4. This truncates the first 4 bits (bit-index) leaving us with the index // into the array. uint256 element = index >> 4; // Mask out the first 4 bytes of the logical index to give us the bit-index. uint8 inside = uint8(index) & 0x0F; // Create a zero mask which will clear the existing value at the bit-index. uint256 zero = ~(uint256(0xFFFF) << (16 * inside)); // Shift the value to the bit index. uint256 shiftedValue = uint256(value) << (16 * inside); // Take the element, apply the zero mask to clear the existing value, and then apply the shifted value with bitwise or. self.data[element] = self.data[element] & zero | shiftedValue; }
// SPDX-License-Identifier: MIT // SPDX-FileCopyrightText: 2023 OpenZeppelin // SPDX-FileCopyrightText: 2023 Snowfork <[email protected]> // Code from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/Math.sol pragma solidity 0.8.25; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Floor, // Toward negative infinity Ceil, // Toward positive infinity Trunc, // Toward zero Expand // Away from 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 Return the log in base 2 of a positive value rounded towards zero. * 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 + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0); } } /** * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers. */ function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) { return uint8(rounding) % 2 == 1; } /** * @dev Safely adds two unsigned 16-bit integers, preventing overflow by saturating to max uint16. */ function saturatingAdd(uint16 a, uint16 b) internal pure returns (uint16) { unchecked { uint16 c = a + b; if (c < a) { return 0xFFFF; } return c; } } /** * @dev Safely subtracts two unsigned 256-bit integers, preventing overflow by saturating to min uint256. */ function saturatingSub(uint256 a, uint256 b) internal pure returns (uint256) { unchecked { if (b >= a) { return 0; } return a - b; } } }
// SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: 2023 Snowfork <[email protected]> pragma solidity 0.8.25; library MMRProof { error ProofSizeExceeded(); uint256 internal constant MAXIMUM_PROOF_SIZE = 256; /** * @dev Verify inclusion of a leaf in an MMR * @param root MMR root hash * @param leafHash leaf hash * @param proof an array of hashes * @param proofOrder a bitfield describing the order of each item (left vs right) */ function verifyLeafProof(bytes32 root, bytes32 leafHash, bytes32[] calldata proof, uint256 proofOrder) internal pure returns (bool) { // Size of the proof is bounded, since `proofOrder` can only contain `MAXIMUM_PROOF_SIZE` orderings. if (proof.length > MAXIMUM_PROOF_SIZE) { revert ProofSizeExceeded(); } bytes32 acc = leafHash; for (uint256 i = 0; i < proof.length; i++) { acc = hashPairs(acc, proof[i], (proofOrder >> i) & 1); } return root == acc; } function hashPairs(bytes32 x, bytes32 y, uint256 order) internal pure returns (bytes32 value) { assembly { switch order case 0 { mstore(0x00, x) mstore(0x20, y) } default { mstore(0x00, y) mstore(0x20, x) } value := keccak256(0x0, 0x40) } } }
// SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: 2023 Snowfork <[email protected]> pragma solidity 0.8.25; library ScaleCodec { error UnsupportedCompactEncoding(); uint256 internal constant MAX_COMPACT_ENCODABLE_UINT = 2 ** 30 - 1; // 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 encodeU256(uint256 input) internal pure returns (bytes32) { return bytes32(reverse256(input)); } function encodeU128(uint128 input) internal pure returns (bytes16) { return bytes16(reverse128(input)); } function encodeU64(uint64 input) internal pure returns (bytes8) { return bytes8(reverse64(input)); } function encodeU32(uint32 input) internal pure returns (bytes4) { return bytes4(reverse32(input)); } function encodeU16(uint16 input) internal pure returns (bytes2) { return bytes2(reverse16(input)); } function encodeU8(uint8 input) internal pure returns (bytes1) { return bytes1(input); } // Supports compact encoding of integers in [0, uint32.MAX] function encodeCompactU32(uint32 value) internal pure returns (bytes memory) { if (value <= 2 ** 6 - 1) { // add single byte flag return abi.encodePacked(uint8(value << 2)); } else if (value <= 2 ** 14 - 1) { // add two byte flag and create little endian encoding return abi.encodePacked(ScaleCodec.reverse16(uint16(((value << 2) + 1)))); } else if (value <= 2 ** 30 - 1) { // add four byte flag and create little endian encoding return abi.encodePacked(ScaleCodec.reverse32(uint32((value << 2)) + 2)); } else { return abi.encodePacked(uint8(3), ScaleCodec.reverse32(value)); } } function checkedEncodeCompactU32(uint256 value) internal pure returns (bytes memory) { if (value > type(uint32).max) { revert UnsupportedCompactEncoding(); } return encodeCompactU32(uint32(value)); } }
// 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 // SPDX-FileCopyrightText: 2023 Snowfork <[email protected]> // Code from https://github.com/ethereum/solidity-examples pragma solidity 0.8.25; library Bits { uint256 internal constant ONE = uint256(1); uint256 internal constant ONES = type(uint256).max; // Sets the bit at the given 'index' in 'self' to '1'. // Returns the modified value. function setBit(uint256 self, uint8 index) internal pure returns (uint256) { return self | (ONE << index); } // Sets the bit at the given 'index' in 'self' to '0'. // Returns the modified value. function clearBit(uint256 self, uint8 index) internal pure returns (uint256) { return self & ~(ONE << index); } // Sets the bit at the given 'index' in 'self' to: // '1' - if the bit is '0' // '0' - if the bit is '1' // Returns the modified value. function toggleBit(uint256 self, uint8 index) internal pure returns (uint256) { return self ^ (ONE << index); } // Get the value of the bit at the given 'index' in 'self'. function bit(uint256 self, uint8 index) internal pure returns (uint8) { return uint8((self >> index) & 1); } // Check if the bit at the given 'index' in 'self' is set. // Returns: // 'true' - if the value of the bit is '1' // 'false' - if the value of the bit is '0' function bitSet(uint256 self, uint8 index) internal pure returns (bool) { return (self >> index) & 1 == 1; } // Checks if the bit at the given 'index' in 'self' is equal to the corresponding // bit in 'other'. // Returns: // 'true' - if both bits are '0' or both bits are '1' // 'false' - otherwise function bitEqual(uint256 self, uint256 other, uint8 index) internal pure returns (bool) { return ((self ^ other) >> index) & 1 == 0; } // Get the bitwise NOT of the bit at the given 'index' in 'self'. function bitNot(uint256 self, uint8 index) internal pure returns (uint8) { return uint8(1 - ((self >> index) & 1)); } // Computes the bitwise AND of the bit at the given 'index' in 'self', and the // corresponding bit in 'other', and returns the value. function bitAnd(uint256 self, uint256 other, uint8 index) internal pure returns (uint8) { return uint8(((self & other) >> index) & 1); } // Computes the bitwise OR of the bit at the given 'index' in 'self', and the // corresponding bit in 'other', and returns the value. function bitOr(uint256 self, uint256 other, uint8 index) internal pure returns (uint8) { return uint8(((self | other) >> index) & 1); } // Computes the bitwise XOR of the bit at the given 'index' in 'self', and the // corresponding bit in 'other', and returns the value. function bitXor(uint256 self, uint256 other, uint8 index) internal pure returns (uint8) { return uint8(((self ^ other) >> index) & 1); } // Gets 'numBits' consecutive bits from 'self', starting from the bit at 'startIndex'. // Returns the bits as a 'uint'. // Requires that: // - '0 < numBits <= 256' // - 'startIndex < 256' // - 'numBits + startIndex <= 256' function bits(uint256 self, uint8 startIndex, uint16 numBits) internal pure returns (uint256) { require(0 < numBits && startIndex < 256 && startIndex + numBits <= 256, "out of bounds"); return (self >> startIndex) & (ONES >> (256 - numBits)); } // Computes the index of the highest bit set in 'self'. // Returns the highest bit set as an 'uint8'. // Requires that 'self != 0'. function highestBitSet(uint256 self) internal pure returns (uint8 highest) { require(self != 0, "should not be zero"); uint256 val = self; for (uint8 i = 128; i >= 1; i >>= 1) { if (val & (((ONE << i) - 1) << i) != 0) { highest += i; val >>= i; } } } // Computes the index of the lowest bit set in 'self'. // Returns the lowest bit set as an 'uint8'. // Requires that 'self != 0'. function lowestBitSet(uint256 self) internal pure returns (uint8 lowest) { require(self != 0, "should not be zero"); uint256 val = self; for (uint8 i = 128; i >= 1; i >>= 1) { if (val & ((ONE << i) - 1) == 0) { lowest += i; val >>= i; } } } }
// 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); } } }
// 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": [ "canonical-weth/=lib/canonical-weth/contracts/", "ds-test/=lib/ds-test/src/", "forge-std/=lib/forge-std/src/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "openzeppelin/=lib/openzeppelin-contracts/contracts/", "prb/math/=lib/prb-math/", "@prb/test/=lib/prb-math/lib/prb-test/src/", "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/", "prb-math/=lib/prb-math/src/", "prb-test/=lib/prb-math/lib/prb-test/src/" ], "optimizer": { "enabled": true, "runs": 20000 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "viaIR": true, "libraries": { "src/Assets.sol": { "Assets": "0xa1BB108073083671DE677Bc5e77274E76b869F6f" }, "src/Verification.sol": { "Verification": "0x280FF90e94f2C531DA969ca94f65C6560b7bf247" } } }
[{"inputs":[{"internalType":"uint256","name":"_randaoCommitDelay","type":"uint256"},{"internalType":"uint256","name":"_randaoCommitExpiration","type":"uint256"},{"internalType":"uint256","name":"_minNumRequiredSignatures","type":"uint256"},{"internalType":"uint64","name":"_initialBeefyBlock","type":"uint64"},{"components":[{"internalType":"uint128","name":"id","type":"uint128"},{"internalType":"uint128","name":"length","type":"uint128"},{"internalType":"bytes32","name":"root","type":"bytes32"}],"internalType":"struct BeefyClient.ValidatorSet","name":"_initialValidatorSet","type":"tuple"},{"components":[{"internalType":"uint128","name":"id","type":"uint128"},{"internalType":"uint128","name":"length","type":"uint128"},{"internalType":"bytes32","name":"root","type":"bytes32"}],"internalType":"struct BeefyClient.ValidatorSet","name":"_nextValidatorSet","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CommitmentNotRelevant","type":"error"},{"inputs":[],"name":"IndexOutOfBounds","type":"error"},{"inputs":[],"name":"InvalidBitfield","type":"error"},{"inputs":[],"name":"InvalidBitfieldLength","type":"error"},{"inputs":[],"name":"InvalidCommitment","type":"error"},{"inputs":[],"name":"InvalidMMRLeaf","type":"error"},{"inputs":[],"name":"InvalidMMRLeafProof","type":"error"},{"inputs":[],"name":"InvalidMMRRootLength","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"InvalidTicket","type":"error"},{"inputs":[],"name":"InvalidValidatorProof","type":"error"},{"inputs":[],"name":"InvalidValidatorProofLength","type":"error"},{"inputs":[],"name":"NotEnoughClaims","type":"error"},{"inputs":[],"name":"PrevRandaoAlreadyCaptured","type":"error"},{"inputs":[],"name":"PrevRandaoNotCaptured","type":"error"},{"inputs":[],"name":"ProofSizeExceeded","type":"error"},{"inputs":[],"name":"StaleCommitment","type":"error"},{"inputs":[],"name":"TicketExpired","type":"error"},{"inputs":[],"name":"UnsupportedCompactEncoding","type":"error"},{"inputs":[],"name":"WaitPeriodNotOver","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"mmrRoot","type":"bytes32"},{"indexed":false,"internalType":"uint64","name":"blockNumber","type":"uint64"}],"name":"NewMMRRoot","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"uint64","name":"blockNumber","type":"uint64"}],"name":"NewTicket","type":"event"},{"inputs":[],"name":"MMR_ROOT_ID","outputs":[{"internalType":"bytes2","name":"","type":"bytes2"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"commitmentHash","type":"bytes32"}],"name":"commitPrevRandao","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"commitmentHash","type":"bytes32"},{"internalType":"uint256[]","name":"bitfield","type":"uint256[]"}],"name":"createFinalBitfield","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"bitsToSet","type":"uint256[]"},{"internalType":"uint256","name":"length","type":"uint256"}],"name":"createInitialBitfield","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"currentValidatorSet","outputs":[{"internalType":"uint128","name":"id","type":"uint128"},{"internalType":"uint128","name":"length","type":"uint128"},{"internalType":"bytes32","name":"root","type":"bytes32"},{"components":[{"internalType":"uint256[]","name":"data","type":"uint256[]"},{"internalType":"uint256","name":"length","type":"uint256"}],"internalType":"struct Uint16Array","name":"usageCounters","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestBeefyBlock","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestMMRRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minNumRequiredSignatures","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextValidatorSet","outputs":[{"internalType":"uint128","name":"id","type":"uint128"},{"internalType":"uint128","name":"length","type":"uint128"},{"internalType":"bytes32","name":"root","type":"bytes32"},{"components":[{"internalType":"uint256[]","name":"data","type":"uint256[]"},{"internalType":"uint256","name":"length","type":"uint256"}],"internalType":"struct Uint16Array","name":"usageCounters","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"randaoCommitDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"randaoCommitExpiration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"blockNumber","type":"uint32"},{"internalType":"uint64","name":"validatorSetID","type":"uint64"},{"components":[{"internalType":"bytes2","name":"payloadID","type":"bytes2"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct BeefyClient.PayloadItem[]","name":"payload","type":"tuple[]"}],"internalType":"struct BeefyClient.Commitment","name":"commitment","type":"tuple"},{"internalType":"uint256[]","name":"bitfield","type":"uint256[]"},{"components":[{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"internalType":"struct BeefyClient.ValidatorProof[]","name":"proofs","type":"tuple[]"},{"components":[{"internalType":"uint8","name":"version","type":"uint8"},{"internalType":"uint32","name":"parentNumber","type":"uint32"},{"internalType":"bytes32","name":"parentHash","type":"bytes32"},{"internalType":"uint64","name":"nextAuthoritySetID","type":"uint64"},{"internalType":"uint32","name":"nextAuthoritySetLen","type":"uint32"},{"internalType":"bytes32","name":"nextAuthoritySetRoot","type":"bytes32"},{"internalType":"bytes32","name":"parachainHeadsRoot","type":"bytes32"}],"internalType":"struct BeefyClient.MMRLeaf","name":"leaf","type":"tuple"},{"internalType":"bytes32[]","name":"leafProof","type":"bytes32[]"},{"internalType":"uint256","name":"leafProofOrder","type":"uint256"}],"name":"submitFinal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"blockNumber","type":"uint32"},{"internalType":"uint64","name":"validatorSetID","type":"uint64"},{"components":[{"internalType":"bytes2","name":"payloadID","type":"bytes2"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct BeefyClient.PayloadItem[]","name":"payload","type":"tuple[]"}],"internalType":"struct BeefyClient.Commitment","name":"commitment","type":"tuple"},{"internalType":"uint256[]","name":"bitfield","type":"uint256[]"},{"components":[{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"internalType":"struct BeefyClient.ValidatorProof","name":"proof","type":"tuple"}],"name":"submitInitial","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"ticketID","type":"bytes32"}],"name":"tickets","outputs":[{"internalType":"uint64","name":"blockNumber","type":"uint64"},{"internalType":"uint32","name":"validatorSetLen","type":"uint32"},{"internalType":"uint32","name":"numRequiredSignatures","type":"uint32"},{"internalType":"uint256","name":"prevRandao","type":"uint256"},{"internalType":"bytes32","name":"bitfieldHash","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"leafHash","type":"bytes32"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"},{"internalType":"uint256","name":"proofOrder","type":"uint256"}],"name":"verifyMMRLeafProof","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
604060e08152346102fc576130d5908138038061001b81610320565b938439820191610140818403126102fc578051602080830151848401516060850151929493926001600160401b03929190838116908190036102fc5761007260809960e061006b828d8b01610359565b9801610359565b9160018060801b0393848451169660019788878b5116018781116102e6578716036102a2578b5260a05260c05284546001600160401b0319161784558451868601519083166001600160801b0319918a1b821617600281905595880151600355946100de90891c6103c0565b9081519586519385851161028c57680100000000000000009384861161028c57896004998a54888c5580891061025d575b5090808d9492989695939801976000988c8a52828a208c8b5b8a8110610239575050505061015a96500151600555835116908a8401518d1b161791826006550151600755891c6103c0565b94855191825194851161022657841161021357508590600854846008558085106101e8575b50019060088152858120905b8381106101d7575050505050015160095551612c9e9182610437833951818181610437015261087c015260a0518181816108bb01526109d5015260c0518181816106960152610c500152f35b82518282015591860191840161018b565b60088452858584862092830192015b82811061020557505061017f565b8581558994508791016101f7565b634e487b7160e01b835260419052602482fd5b634e487b7160e01b845260418252602484fd5b9193969899959750919384519401938184015501918e9593979694918c8f94610128565b60008c6000528b8a8560002093840193015b83811061027e5750505061010f565b8281558f95508d910161026f565b634e487b7160e01b600052604160045260246000fd5b8a5162461bcd60e51b8152600481018b9052601a60248201527f696e76616c69642d636f6e7374727563746f722d706172616d730000000000006044820152606490fd5b634e487b7160e01b600052601160045260246000fd5b600080fd5b60408051919082016001600160401b0381118382101761028c57604052565b6040519190601f01601f191682016001600160401b0381118382101761028c57604052565b51906001600160801b03821682036102fc57565b91908260609103126102fc57604051606081016001600160401b0381118282101761028c57604052604080829461038f81610345565b845261039d60208201610345565b60208501520151910152565b6001600160401b03811161028c5760051b60200190565b600060206103cc610301565b6060815201528060041c90600f81161560001461042d5760ff60005b1682018092116102e6576104036103fe836103a9565b610320565b91808352610413601f19916103a9565b01366020840137610422610301565b918252602082015290565b60ff60016103e856fe6080604052600436101561001257600080fd5b60003560e01c80630a7c8faa146101075780632cdea7171461010257806336667513146100fd57806341c9634e146100f8578063591d99ee146100f35780635da57fe9146100ee578063623b223d146100e957806366ae69a0146100e45780636f55bd32146100df5780638ab81d13146100da578063a401662b146100d5578063a77cf3d2146100d0578063ad209a9b146100cb578063bb51f1eb146100c65763df0dd0d5146100c157600080fd5b610eee565b6109f8565b6109bd565b610812565b6107c3565b6106b9565b61067e565b610656565b6105bd565b6104c7565b61041f565b610401565b610342565b61027f565b346101425760006003193601126101425760206040517f6d680000000000000000000000000000000000000000000000000000000000008152f35b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040810190811067ffffffffffffffff82111761019257604052565b610147565b60a0810190811067ffffffffffffffff82111761019257604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761019257604052565b6040519061020182610197565b565b92909391936fffffffffffffffffffffffffffffffff809116845260209416602084015260408301526080606083015260c0820192815193604060808501528451809152602060e0850195019160005b82811061026b5750505050602060a091015191015290565b835187529581019592810192600101610253565b3461014257600060031936011261014257600254600354604051916102a383610176565b60405192836004549485815260208091019560046000527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b916000905b82821061032b57878761032788886102fa818f03826101b3565b8152600554602082015260405193836fffffffffffffffffffffffffffffffff869560801c911685610203565b0390f35b8354895297880197600193840193909101906102e0565b34610142576000600319360112610142576006546007546040519161036683610176565b60405192836008549485815260208091019560086000527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee3916000905b8282106103ea57878761032788886103bd818f03826101b3565b8152600954602082015260405193836fffffffffffffffffffffffffffffffff869560801c911685610203565b8354895297880197600193840193909101906103a3565b34610142576000600319360112610142576020600054604051908152f35b346101425760006003193601126101425760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b9181601f840112156101425782359167ffffffffffffffff8311610142576020808501948460051b01011161014257565b602090602060408183019282815285518094520193019160005b8281106104b3575050505090565b8351855293810193928101926001016104a5565b346101425760406003193601126101425760043567ffffffffffffffff8111610142576104f890369060040161045a565b906024358281106105565760ff81018091116105515761051a9060081c611636565b9160005b8181106105335760405180610327868261048b565b8061054b61054460019385876116b4565b3586612571565b0161051e565b610f6b565b60046040517f5c85a0e7000000000000000000000000000000000000000000000000000000008152fd5b908160609103126101425790565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9c60e091011261014257606490565b34610142576101806003193601126101425767ffffffffffffffff600435818111610142576105f0903690600401610580565b6024358281116101425761060890369060040161045a565b906044358481116101425761062190369060040161045a565b61062a3661058e565b91610144359687116101425761064761065497369060040161045a565b95909461016435976111bf565b005b3461014257600060031936011261014257602067ffffffffffffffff60015416604051908152f35b346101425760006003193601126101425760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b34610142576040806003193601126101425760243567ffffffffffffffff8111610142576106eb90369060040161045a565b9190913360005260043560205261070f82600020600052600a602052604060002090565b6002810154835160208101906107568161072a84888b61150c565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018352826101b3565b5190200361079a579261078f9184610789600161032797015491549363ffffffff8086891c169560601c16933691611558565b90612056565b90519182918261048b565b600483517f6768c0aa000000000000000000000000000000000000000000000000000000008152fd5b346101425760606003193601126101425760243567ffffffffffffffff8111610142576108086107f9602092369060040161045a565b60443591600435600054611f6b565b6040519015158152f35b346101425760206003193601126101425761083860043533600052602052604060002090565b61084c81600052600a602052604060002090565b9067ffffffffffffffff610868835467ffffffffffffffff1690565b1691821561099357600101918254610969577f0000000000000000000000000000000000000000000000000000000000000000906108a682826115a6565b431061093f576108e0916108b9916115a6565b7f0000000000000000000000000000000000000000000000000000000000000000906115a6565b43116108ec5750449055005b61090361091591600052600a602052604060002090565b60026000918281558260018201550155565b60046040517f40d35447000000000000000000000000000000000000000000000000000000008152fd5b60046040517fc77c1949000000000000000000000000000000000000000000000000000000008152fd5b60046040517fe31d9005000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6686db64000000000000000000000000000000000000000000000000000000008152fd5b346101425760006003193601126101425760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346101425760031960608136011261014257600467ffffffffffffffff813581811161014257610a2b9036908401610580565b9160243582811161014257610a43903690830161045a565b94604435958487116101425760c087850192883603011261014257610a67866110e5565b91610a8b610a7e60015467ffffffffffffffff1690565b67ffffffffffffffff1690565b63ffffffff8094161115610ec55760208701610aa681610f56565b87610ada610ac56002546fffffffffffffffffffffffffffffffff1690565b6fffffffffffffffffffffffffffffffff1690565b911603610e435750606488013590610b04610af48361218d565b92610afe846121e0565b90612268565b6002905b60848a019060a4610b3e610b3a8d610b1f866115b3565b610b31606483013595869301876115d4565b929091896122ca565b1590565b908115610e24575b50610dfb57610bb7610b9e610b988c9d73ffffffffffffffffffffffffffffffffffffffff94610b79610b889e9f611789565b602081519101209d8e91611628565b6024604484013593013591612352565b936115b3565b73ffffffffffffffffffffffffffffffffffffffff1690565b911603610dd257610bdc610bd4610bcf368689611558565b612369565b915460801c90565b956fffffffffffffffffffffffffffffffff871691610bfa836124c1565b11610daa5750610da596610d8896610cd08b97610cc3610d83987fbee983fc706c692efb9b0240bddc5666c010a53af55ed5fb42d226e7e42938699d9861072a610c93610c80610c77610cfb9c610ceb9c61ffff7f00000000000000000000000000000000000000000000000000000000000000009216906124fb565b63ffffffff1690565b956040519283916020830195869161150c565b51902094610cb5610ca26101f4565b9a43168b9067ffffffffffffffff169052565b1663ffffffff166020890152565b63ffffffff166040870152565b60006060860152608085015233600052602052604060002090565b600052600a602052604060002090565b8151815460208401516040808601517fffffffffffffffffffffffffffffffff0000000000000000000000000000000090931667ffffffffffffffff9490941693909317921b6bffffffff00000000000000001691909117606091821b6fffffffff000000000000000000000000161782558201516001820155608090910151600290910155565b6110e5565b6040805133815263ffffffff909216602083015290918291820190565b0390a1005b6040517fee3e74af000000000000000000000000000000000000000000000000000000008152fd5b856040517f8baa579f000000000000000000000000000000000000000000000000000000008152fd5b876040517fe00153fa000000000000000000000000000000000000000000000000000000008152fd5b610e3d9150610b3a90610e3836898c611558565b612335565b38610b46565b610e4c90610f56565b86610e6b610ac56006546fffffffffffffffffffffffffffffffff1690565b911603610e9c57606488013590610e94610e848361210a565b92610e8e846121e0565b906121fb565b600690610b08565b846040517fc06789fa000000000000000000000000000000000000000000000000000000008152fd5b846040517f3d618e50000000000000000000000000000000000000000000000000000000008152fd5b3461014257602060031936011261014257600435600052600a60205260a0604060002080549063ffffffff9060026001820154910154916040519367ffffffffffffffff81168552818160401c16602086015260601c16604084015260608301526080820152f35b3567ffffffffffffffff811681036101425790565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9060016fffffffffffffffffffffffffffffffff8093160191821161055157565b6006546fffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffff00000000000000000000000000000000821691161760025560075460035560085467ffffffffffffffff81116101925768010000000000000000811161019257600454816004558082106110a4575b50600460009081527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee380545b83831061106e5750505050600954600555565b60018091920192835492817f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b015501919061105b565b817f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b91820191015b8181106110d9575061102f565b600081556001016110cc565b3563ffffffff811681036101425790565b805180519067ffffffffffffffff821161019257680100000000000000008211610192576008548260085580831061117e575b50602080910190600860005260005b83811061114c575050505060200151600955565b82517ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee382015591810191600101611138565b827ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee391820191015b8181106111b35750611129565b600081556001016111a6565b9790969295919493946111d189611789565b60208151910120956111ec8733600052602052604060002090565b976111f9838b8d8c611950565b60009760208c019361120a85610f56565b996112266006546fffffffffffffffffffffffffffffffff1690565b9567ffffffffffffffff9b8c6fffffffffffffffffffffffffffffffff891691161460001461149f5750509061126493929160019c8c600693611aa5565b61126d89611d54565b97611306575b5050505050507fd95fe1258d152dc91c81b09380498adc76ed36a6079bcb2ed31eff622ae2d0f192610d836109036112ed9385600055610ceb6112b8610c77866110e5565b67ffffffffffffffff167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000006001541617600155565b6040805192835263ffffffff91909116602083015290a1565b606085019895611321610ac561131b8c610f56565b93610f9a565b9116036114755761134692610b3a9261133986611e85565b6020815191012089611f6b565b61144b576109036112ed9361144261143d611438610c77610d83966113d6611399610a7e7fd95fe1258d152dc91c81b09380498adc76ed36a6079bcb2ed31eff622ae2d0f19e611394610fbb565b610f56565b6fffffffffffffffffffffffffffffffff167fffffffffffffffffffffffffffffffff000000000000000000000000000000006006541617600655565b610d8360a060808301926114316113ef610c77866110e5565b6fffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffff000000000000000000000000000000006006549260801b16911617600655565b0135600755565b611ff7565b6110f6565b93839638611273565b60046040517f128597bb000000000000000000000000000000000000000000000000000000008152fd5b60046040517fc72c8200000000000000000000000000000000000000000000000000000000008152fd5b6114af909d95949392919d610f56565b8b6114ce610ac56002546fffffffffffffffffffffffffffffffff1690565b9116036114e257611264948c600293611aa5565b60046040517fc06789fa000000000000000000000000000000000000000000000000000000008152fd5b91907f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81116101425760051b809282370190565b67ffffffffffffffff81116101925760051b60200190565b929161156382611540565b9161157160405193846101b3565b829481845260208094019160051b810192831161014257905b8282106115975750505050565b8135815290830190830161158a565b9190820180921161055157565b3573ffffffffffffffffffffffffffffffffffffffff811681036101425790565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610142570180359067ffffffffffffffff821161014257602001918160051b3603831361014257565b3560ff811681036101425790565b9061164082611540565b61164d60405191826101b3565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061167b8294611540565b0190602036910137565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b91908110156116c45760051b0190565b611685565b9081519160005b8381106116e1575050016000815290565b80602080928401015181850152016116d0565b600c90610201927fffffffffffffffff00000000000000000000000000000000000000000000000061175296957fffffffff0000000000000000000000000000000000000000000000000000000060405198899560208701906116c9565b93168352166004820152037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec8101855201836101b3565b90604061179960408401846115d4565b91906117a483612a1e565b92600080935b828510611870575050505050826118676117db60206117d46117cf61186d97986110e5565b612597565b9301610f56565b7fffffffffffffffff0000000000000000000000000000000000000000000000009065ffffffffffff8160081c9160081b9166ff000000ff000067ff000000ff00000067ffffffffffff000065ff000000ff00861664ff000000ff85161760101b16941691161760101c161763ffffffff67ffffffff000000008260201b169160201c161760c01b1690565b916116f4565b90565b909192939460019061194587600287896119126118d16118c86118a7876118a061189b828989611c5b565b611c9b565b9686611c5b565b968d6118c26118bb60209a8b810190611cc8565b9050612a1e565b95611c5b565b86810190611cc8565b94859391947fffff0000000000000000000000000000000000000000000000000000000000006119078d519b8c9a8b01906116c9565b9116815201906116c9565b91823701868152037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018352826101b3565b9501939291906117aa565b61196790939293600052600a602052604060002090565b9067ffffffffffffffff611983835467ffffffffffffffff1690565b161561099357600182015415611a3b5761199c906110e5565b63ffffffff6119b7610a7e60015467ffffffffffffffff1690565b91161115611a11576119dd600261072a920154936040519283916020830195869161150c565b519020036119e757565b60046040517f6768c0aa000000000000000000000000000000000000000000000000000000008152fd5b60046040517f3d618e50000000000000000000000000000000000000000000000000000000008152fd5b60046040517f78ef3a47000000000000000000000000000000000000000000000000000000008152fd5b91908110156116c45760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4181360301821215610142570190565b91959290611abd90600052600a602052604060002090565b95611ad3610c77885463ffffffff9060601c1690565b808503611c3157611b14926fffffffffffffffffffffffffffffffff611b0c6001809b015494611b048a5460801c90565b933691611558565b911692612056565b9160005b818110611b285750505050505050565b611b33818388611a65565b606081013590611b578980611b4b8560081c8a612321565b5160ff86161c16141590565b611c075760808101611b85610b3a84611b6f846115b3565b611b7c60a08701876115d4565b9290918d6122ca565b611c075773ffffffffffffffffffffffffffffffffffffffff611bc4610b9e610b98611bb086611628565b95604096602088830135920135908c612352565b911603611bde575090611bd88892866125ed565b01611b18565b600490517f8baa579f000000000000000000000000000000000000000000000000000000008152fd5b60046040517fe00153fa000000000000000000000000000000000000000000000000000000008152fd5b60046040517f1f1711da000000000000000000000000000000000000000000000000000000008152fd5b91908110156116c45760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc181360301821215610142570190565b357fffff000000000000000000000000000000000000000000000000000000000000811681036101425790565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610142570180359067ffffffffffffffff82116101425760200191813603831361014257565b359060208110611d27575090565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9060200360031b1b1690565b6000905b604091828201611d6881846115d4565b9050821015611e5b577f6d68000000000000000000000000000000000000000000000000000000000000611dd1611dac61189b85611da686896115d4565b90611c5b565b7fffff0000000000000000000000000000000000000000000000000000000000001690565b14611de157506001019150611d58565b82611df383611da684611e01976115d4565b602094818680930190611cc8565b90501415600014611e3557600485517f7df9c486000000000000000000000000000000000000000000000000000000008152fd5b61186d945091611da6611e4c92611e5595946115d4565b90810190611cc8565b90611d19565b60046040517f484ab7df000000000000000000000000000000000000000000000000000000008152fd5b60c07fff00000000000000000000000000000000000000000000000000000000000000611eb183611628565b60f81b1691611ec56117cf602083016110e5565b611ed46117db60608401610f56565b7fffffffffffffffff000000000000000000000000000000000000000000000000611f046117cf608086016110e5565b916040519660208801527fffffffff0000000000000000000000000000000000000000000000000000000080941660218801526040850135602588015216604586015216604d84015260a08101356051840152013560718201526071815261186d81610197565b92906101008211611fcd5793600092918391905b808510611f8f5750505050501490565b9091929395611f9f8783876116b4565b3583881c60011615611fc25784526020525b600160408420960193929190611f7f565b908452602052611fb1565b60046040517f5e862a8a000000000000000000000000000000000000000000000000000000008152fd5b6000602060405161200781610176565b6060815201528060041c600f82161560001461204d5760ff60005b1681018091116105515761203590611636565b906040519161204383610176565b8252602082015290565b60ff6001612022565b9190916120638351611636565b93600091825b8481106120795750505050505090565b816000528360205282604060002006908160081c916120988389612321565b519260ff82169360019485808093831c1614928315936120db575b5050506120d257906120c683928a612571565b019301935b9392612069565b509301936120cb565b8293506120e8908d612321565b51901c16148338806120b3565b60041b90610ff060f083169216820361055157565b600954811015612163578060041c906008548210156116c45760ff61215d600f61ffff9460086000527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee3015493166120f5565b161c1690565b60046040517f4e23d035000000000000000000000000000000000000000000000000000000008152fd5b600554811015612163578060041c906004548210156116c45760ff61215d600f61ffff9460046000527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b015493166120f5565b61ffff80806001840116921682106121f6575090565b905090565b60095481101561216357600f8160041c911660ff61222b61ffff8083612220866120f5565b161b199516926120f5565b161b906008548110156116c4577ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee301918254161790600860005255565b60055481101561216357600f8160041c911660ff61228d61ffff8083612220866120f5565b161b906004548110156116c4577f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b01918254161790600460005255565b909161186d9493926040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000602082019260601b1682526014815261230e81610176565b5190206001830154925460801c92612611565b80518210156116c45760209160051b010190565b60019160ff61234984938360081c90612321565b5191161c161490565b9161186d9391612361936126f3565b9190916127c8565b906000805b83518210156124bc576001906123848386612321565b517f55555555555555555555555555555555555555555555555555555555555555558082851c169116017f3333333333333333333333333333333333333333333333333333333333333333808260021c169116017f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f808260041c169116017eff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff808260081c169116017dffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff808260101c169116017bffffffff00000000ffffffff00000000ffffffff00000000ffffffff808260201c1691160177ffffffffffffffff0000000000000000ffffffffffffffff808260401c169116016fffffffffffffffffffffffffffffffff8160801c9116010191019061236e565b925050565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818111610551576003900481039081116105515790565b9061250582612951565b83018093116105515761251790612951565b8060011b907f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81160361055157806001016001116105515760019083010180921161055157612565906124c1565b808210156121f6575090565b90612594908060081c90600160ff6125898487612321565b5192161b1792612321565b52565b6125e67fffffffff000000000000000000000000000000000000000000000000000000009162ff00ff63ff00ff008260081b169160081c161761ffff63ffff00008260101b169160101c161790565b60e01b1690565b90612594908060081c90600160ff6126058487612321565b5192161b191692612321565b939294919094808210156126e857909291906000905b8282106126375750505050501490565b9091929395600190819081808a161480156126dd575b1561269e5761265d8587896116b4565b356000526020527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6040600020985b821c9301811c01920190939291612627565b6126a98587896116b4565b35906000526020527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60406000209861268c565b5083828a011461264d565b505050505050600090565b9291907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083116127835791608094939160ff602094604051948552168484015260408301526060820152600093849182805260015afa1561277657815173ffffffffffffffffffffffffffffffffffffffff811615612770579190565b50600190565b50604051903d90823e3d90fd5b50505050600090600390565b6005111561279957565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6127d18161278f565b806127d95750565b6127e28161278f565b60018103612849576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606490fd5b6128528161278f565b600281036128b9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606490fd5b806128c560039261278f565b146128cc57565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608490fd5b806000918160801c80612a12575b508060401c80612a05575b508060201c806129f8575b508060101c806129eb575b508060081c806129de575b508060041c806129d1575b508060021c806129c4575b5060011c6129ba575b6001821b101561186d5760010190565b90600101906129aa565b60029150920191386129a1565b6004915092019138612996565b600891509201913861298b565b6010915092019138612980565b6020915092019138612975565b604091509201913861296a565b6080935090503861295f565b63ffffffff808211612a345761186d9116612a88565b60046040517fe809999a000000000000000000000000000000000000000000000000000000008152fd5b90600263ffffffff8093160191821161055157565b90600163ffffffff8093160191821161055157565b63ffffffff8116603f8111612ad5575060405160fa9190911b7ffc0000000000000000000000000000000000000000000000000000000000000016602082015261186d816021810161072a565b613fff8111612b4f575061186d612b17612b04612afd63fffffffc61072a9560021b16612a73565b61ffff1690565b60ff61ff008260081b169160081c161790565b604051928391602083017fffff00000000000000000000000000000000000000000000000000000000000060029260f01b1681520190565b633fffffff10612bd65761186d612b9e612b7463fffffffc61072a9460021b16612a5e565b62ff00ff63ff00ff008260081b169160081c161761ffff63ffff00008260101b169160101c161790565b604051928391602083017fffffffff0000000000000000000000000000000000000000000000000000000060049260e01b1681520190565b61186d612c0a61072a9262ff00ff63ff00ff008260081b169160081c161761ffff63ffff00008260101b169160101c161790565b604051928391602083017fffffffff000000000000000000000000000000000000000000000000000000006005927f0300000000000000000000000000000000000000000000000000000000000000835260e01b166001820152019056fea2646970667358221220c46c43127ee70fb5d31894dd32138d636a39b1aca030fef926ab751d1aefc58a64736f6c63430008190033000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000029048b00000000000000000000000000000000000000000000000000000000000011c1000000000000000000000000000000000000000000000000000000000000005dacb0d61a25cb582707310607640e8c46a12c006b9b0b27861a4eac59e37da10700000000000000000000000000000000000000000000000000000000000011c2000000000000000000000000000000000000000000000000000000000000005dacb0d61a25cb582707310607640e8c46a12c006b9b0b27861a4eac59e37da107
Deployed Bytecode
0x6080604052600436101561001257600080fd5b60003560e01c80630a7c8faa146101075780632cdea7171461010257806336667513146100fd57806341c9634e146100f8578063591d99ee146100f35780635da57fe9146100ee578063623b223d146100e957806366ae69a0146100e45780636f55bd32146100df5780638ab81d13146100da578063a401662b146100d5578063a77cf3d2146100d0578063ad209a9b146100cb578063bb51f1eb146100c65763df0dd0d5146100c157600080fd5b610eee565b6109f8565b6109bd565b610812565b6107c3565b6106b9565b61067e565b610656565b6105bd565b6104c7565b61041f565b610401565b610342565b61027f565b346101425760006003193601126101425760206040517f6d680000000000000000000000000000000000000000000000000000000000008152f35b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040810190811067ffffffffffffffff82111761019257604052565b610147565b60a0810190811067ffffffffffffffff82111761019257604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761019257604052565b6040519061020182610197565b565b92909391936fffffffffffffffffffffffffffffffff809116845260209416602084015260408301526080606083015260c0820192815193604060808501528451809152602060e0850195019160005b82811061026b5750505050602060a091015191015290565b835187529581019592810192600101610253565b3461014257600060031936011261014257600254600354604051916102a383610176565b60405192836004549485815260208091019560046000527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b916000905b82821061032b57878761032788886102fa818f03826101b3565b8152600554602082015260405193836fffffffffffffffffffffffffffffffff869560801c911685610203565b0390f35b8354895297880197600193840193909101906102e0565b34610142576000600319360112610142576006546007546040519161036683610176565b60405192836008549485815260208091019560086000527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee3916000905b8282106103ea57878761032788886103bd818f03826101b3565b8152600954602082015260405193836fffffffffffffffffffffffffffffffff869560801c911685610203565b8354895297880197600193840193909101906103a3565b34610142576000600319360112610142576020600054604051908152f35b346101425760006003193601126101425760206040517f00000000000000000000000000000000000000000000000000000000000000808152f35b9181601f840112156101425782359167ffffffffffffffff8311610142576020808501948460051b01011161014257565b602090602060408183019282815285518094520193019160005b8281106104b3575050505090565b8351855293810193928101926001016104a5565b346101425760406003193601126101425760043567ffffffffffffffff8111610142576104f890369060040161045a565b906024358281106105565760ff81018091116105515761051a9060081c611636565b9160005b8181106105335760405180610327868261048b565b8061054b61054460019385876116b4565b3586612571565b0161051e565b610f6b565b60046040517f5c85a0e7000000000000000000000000000000000000000000000000000000008152fd5b908160609103126101425790565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9c60e091011261014257606490565b34610142576101806003193601126101425767ffffffffffffffff600435818111610142576105f0903690600401610580565b6024358281116101425761060890369060040161045a565b906044358481116101425761062190369060040161045a565b61062a3661058e565b91610144359687116101425761064761065497369060040161045a565b95909461016435976111bf565b005b3461014257600060031936011261014257602067ffffffffffffffff60015416604051908152f35b346101425760006003193601126101425760206040517f00000000000000000000000000000000000000000000000000000000000000108152f35b34610142576040806003193601126101425760243567ffffffffffffffff8111610142576106eb90369060040161045a565b9190913360005260043560205261070f82600020600052600a602052604060002090565b6002810154835160208101906107568161072a84888b61150c565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018352826101b3565b5190200361079a579261078f9184610789600161032797015491549363ffffffff8086891c169560601c16933691611558565b90612056565b90519182918261048b565b600483517f6768c0aa000000000000000000000000000000000000000000000000000000008152fd5b346101425760606003193601126101425760243567ffffffffffffffff8111610142576108086107f9602092369060040161045a565b60443591600435600054611f6b565b6040519015158152f35b346101425760206003193601126101425761083860043533600052602052604060002090565b61084c81600052600a602052604060002090565b9067ffffffffffffffff610868835467ffffffffffffffff1690565b1691821561099357600101918254610969577f0000000000000000000000000000000000000000000000000000000000000080906108a682826115a6565b431061093f576108e0916108b9916115a6565b7f0000000000000000000000000000000000000000000000000000000000000006906115a6565b43116108ec5750449055005b61090361091591600052600a602052604060002090565b60026000918281558260018201550155565b60046040517f40d35447000000000000000000000000000000000000000000000000000000008152fd5b60046040517fc77c1949000000000000000000000000000000000000000000000000000000008152fd5b60046040517fe31d9005000000000000000000000000000000000000000000000000000000008152fd5b60046040517f6686db64000000000000000000000000000000000000000000000000000000008152fd5b346101425760006003193601126101425760206040517f00000000000000000000000000000000000000000000000000000000000000068152f35b346101425760031960608136011261014257600467ffffffffffffffff813581811161014257610a2b9036908401610580565b9160243582811161014257610a43903690830161045a565b94604435958487116101425760c087850192883603011261014257610a67866110e5565b91610a8b610a7e60015467ffffffffffffffff1690565b67ffffffffffffffff1690565b63ffffffff8094161115610ec55760208701610aa681610f56565b87610ada610ac56002546fffffffffffffffffffffffffffffffff1690565b6fffffffffffffffffffffffffffffffff1690565b911603610e435750606488013590610b04610af48361218d565b92610afe846121e0565b90612268565b6002905b60848a019060a4610b3e610b3a8d610b1f866115b3565b610b31606483013595869301876115d4565b929091896122ca565b1590565b908115610e24575b50610dfb57610bb7610b9e610b988c9d73ffffffffffffffffffffffffffffffffffffffff94610b79610b889e9f611789565b602081519101209d8e91611628565b6024604484013593013591612352565b936115b3565b73ffffffffffffffffffffffffffffffffffffffff1690565b911603610dd257610bdc610bd4610bcf368689611558565b612369565b915460801c90565b956fffffffffffffffffffffffffffffffff871691610bfa836124c1565b11610daa5750610da596610d8896610cd08b97610cc3610d83987fbee983fc706c692efb9b0240bddc5666c010a53af55ed5fb42d226e7e42938699d9861072a610c93610c80610c77610cfb9c610ceb9c61ffff7f00000000000000000000000000000000000000000000000000000000000000109216906124fb565b63ffffffff1690565b956040519283916020830195869161150c565b51902094610cb5610ca26101f4565b9a43168b9067ffffffffffffffff169052565b1663ffffffff166020890152565b63ffffffff166040870152565b60006060860152608085015233600052602052604060002090565b600052600a602052604060002090565b8151815460208401516040808601517fffffffffffffffffffffffffffffffff0000000000000000000000000000000090931667ffffffffffffffff9490941693909317921b6bffffffff00000000000000001691909117606091821b6fffffffff000000000000000000000000161782558201516001820155608090910151600290910155565b6110e5565b6040805133815263ffffffff909216602083015290918291820190565b0390a1005b6040517fee3e74af000000000000000000000000000000000000000000000000000000008152fd5b856040517f8baa579f000000000000000000000000000000000000000000000000000000008152fd5b876040517fe00153fa000000000000000000000000000000000000000000000000000000008152fd5b610e3d9150610b3a90610e3836898c611558565b612335565b38610b46565b610e4c90610f56565b86610e6b610ac56006546fffffffffffffffffffffffffffffffff1690565b911603610e9c57606488013590610e94610e848361210a565b92610e8e846121e0565b906121fb565b600690610b08565b846040517fc06789fa000000000000000000000000000000000000000000000000000000008152fd5b846040517f3d618e50000000000000000000000000000000000000000000000000000000008152fd5b3461014257602060031936011261014257600435600052600a60205260a0604060002080549063ffffffff9060026001820154910154916040519367ffffffffffffffff81168552818160401c16602086015260601c16604084015260608301526080820152f35b3567ffffffffffffffff811681036101425790565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9060016fffffffffffffffffffffffffffffffff8093160191821161055157565b6006546fffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffff00000000000000000000000000000000821691161760025560075460035560085467ffffffffffffffff81116101925768010000000000000000811161019257600454816004558082106110a4575b50600460009081527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee380545b83831061106e5750505050600954600555565b60018091920192835492817f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b015501919061105b565b817f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b91820191015b8181106110d9575061102f565b600081556001016110cc565b3563ffffffff811681036101425790565b805180519067ffffffffffffffff821161019257680100000000000000008211610192576008548260085580831061117e575b50602080910190600860005260005b83811061114c575050505060200151600955565b82517ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee382015591810191600101611138565b827ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee391820191015b8181106111b35750611129565b600081556001016111a6565b9790969295919493946111d189611789565b60208151910120956111ec8733600052602052604060002090565b976111f9838b8d8c611950565b60009760208c019361120a85610f56565b996112266006546fffffffffffffffffffffffffffffffff1690565b9567ffffffffffffffff9b8c6fffffffffffffffffffffffffffffffff891691161460001461149f5750509061126493929160019c8c600693611aa5565b61126d89611d54565b97611306575b5050505050507fd95fe1258d152dc91c81b09380498adc76ed36a6079bcb2ed31eff622ae2d0f192610d836109036112ed9385600055610ceb6112b8610c77866110e5565b67ffffffffffffffff167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000006001541617600155565b6040805192835263ffffffff91909116602083015290a1565b606085019895611321610ac561131b8c610f56565b93610f9a565b9116036114755761134692610b3a9261133986611e85565b6020815191012089611f6b565b61144b576109036112ed9361144261143d611438610c77610d83966113d6611399610a7e7fd95fe1258d152dc91c81b09380498adc76ed36a6079bcb2ed31eff622ae2d0f19e611394610fbb565b610f56565b6fffffffffffffffffffffffffffffffff167fffffffffffffffffffffffffffffffff000000000000000000000000000000006006541617600655565b610d8360a060808301926114316113ef610c77866110e5565b6fffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffff000000000000000000000000000000006006549260801b16911617600655565b0135600755565b611ff7565b6110f6565b93839638611273565b60046040517f128597bb000000000000000000000000000000000000000000000000000000008152fd5b60046040517fc72c8200000000000000000000000000000000000000000000000000000000008152fd5b6114af909d95949392919d610f56565b8b6114ce610ac56002546fffffffffffffffffffffffffffffffff1690565b9116036114e257611264948c600293611aa5565b60046040517fc06789fa000000000000000000000000000000000000000000000000000000008152fd5b91907f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81116101425760051b809282370190565b67ffffffffffffffff81116101925760051b60200190565b929161156382611540565b9161157160405193846101b3565b829481845260208094019160051b810192831161014257905b8282106115975750505050565b8135815290830190830161158a565b9190820180921161055157565b3573ffffffffffffffffffffffffffffffffffffffff811681036101425790565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610142570180359067ffffffffffffffff821161014257602001918160051b3603831361014257565b3560ff811681036101425790565b9061164082611540565b61164d60405191826101b3565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061167b8294611540565b0190602036910137565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b91908110156116c45760051b0190565b611685565b9081519160005b8381106116e1575050016000815290565b80602080928401015181850152016116d0565b600c90610201927fffffffffffffffff00000000000000000000000000000000000000000000000061175296957fffffffff0000000000000000000000000000000000000000000000000000000060405198899560208701906116c9565b93168352166004820152037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec8101855201836101b3565b90604061179960408401846115d4565b91906117a483612a1e565b92600080935b828510611870575050505050826118676117db60206117d46117cf61186d97986110e5565b612597565b9301610f56565b7fffffffffffffffff0000000000000000000000000000000000000000000000009065ffffffffffff8160081c9160081b9166ff000000ff000067ff000000ff00000067ffffffffffff000065ff000000ff00861664ff000000ff85161760101b16941691161760101c161763ffffffff67ffffffff000000008260201b169160201c161760c01b1690565b916116f4565b90565b909192939460019061194587600287896119126118d16118c86118a7876118a061189b828989611c5b565b611c9b565b9686611c5b565b968d6118c26118bb60209a8b810190611cc8565b9050612a1e565b95611c5b565b86810190611cc8565b94859391947fffff0000000000000000000000000000000000000000000000000000000000006119078d519b8c9a8b01906116c9565b9116815201906116c9565b91823701868152037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018352826101b3565b9501939291906117aa565b61196790939293600052600a602052604060002090565b9067ffffffffffffffff611983835467ffffffffffffffff1690565b161561099357600182015415611a3b5761199c906110e5565b63ffffffff6119b7610a7e60015467ffffffffffffffff1690565b91161115611a11576119dd600261072a920154936040519283916020830195869161150c565b519020036119e757565b60046040517f6768c0aa000000000000000000000000000000000000000000000000000000008152fd5b60046040517f3d618e50000000000000000000000000000000000000000000000000000000008152fd5b60046040517f78ef3a47000000000000000000000000000000000000000000000000000000008152fd5b91908110156116c45760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4181360301821215610142570190565b91959290611abd90600052600a602052604060002090565b95611ad3610c77885463ffffffff9060601c1690565b808503611c3157611b14926fffffffffffffffffffffffffffffffff611b0c6001809b015494611b048a5460801c90565b933691611558565b911692612056565b9160005b818110611b285750505050505050565b611b33818388611a65565b606081013590611b578980611b4b8560081c8a612321565b5160ff86161c16141590565b611c075760808101611b85610b3a84611b6f846115b3565b611b7c60a08701876115d4565b9290918d6122ca565b611c075773ffffffffffffffffffffffffffffffffffffffff611bc4610b9e610b98611bb086611628565b95604096602088830135920135908c612352565b911603611bde575090611bd88892866125ed565b01611b18565b600490517f8baa579f000000000000000000000000000000000000000000000000000000008152fd5b60046040517fe00153fa000000000000000000000000000000000000000000000000000000008152fd5b60046040517f1f1711da000000000000000000000000000000000000000000000000000000008152fd5b91908110156116c45760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc181360301821215610142570190565b357fffff000000000000000000000000000000000000000000000000000000000000811681036101425790565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610142570180359067ffffffffffffffff82116101425760200191813603831361014257565b359060208110611d27575090565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9060200360031b1b1690565b6000905b604091828201611d6881846115d4565b9050821015611e5b577f6d68000000000000000000000000000000000000000000000000000000000000611dd1611dac61189b85611da686896115d4565b90611c5b565b7fffff0000000000000000000000000000000000000000000000000000000000001690565b14611de157506001019150611d58565b82611df383611da684611e01976115d4565b602094818680930190611cc8565b90501415600014611e3557600485517f7df9c486000000000000000000000000000000000000000000000000000000008152fd5b61186d945091611da6611e4c92611e5595946115d4565b90810190611cc8565b90611d19565b60046040517f484ab7df000000000000000000000000000000000000000000000000000000008152fd5b60c07fff00000000000000000000000000000000000000000000000000000000000000611eb183611628565b60f81b1691611ec56117cf602083016110e5565b611ed46117db60608401610f56565b7fffffffffffffffff000000000000000000000000000000000000000000000000611f046117cf608086016110e5565b916040519660208801527fffffffff0000000000000000000000000000000000000000000000000000000080941660218801526040850135602588015216604586015216604d84015260a08101356051840152013560718201526071815261186d81610197565b92906101008211611fcd5793600092918391905b808510611f8f5750505050501490565b9091929395611f9f8783876116b4565b3583881c60011615611fc25784526020525b600160408420960193929190611f7f565b908452602052611fb1565b60046040517f5e862a8a000000000000000000000000000000000000000000000000000000008152fd5b6000602060405161200781610176565b6060815201528060041c600f82161560001461204d5760ff60005b1681018091116105515761203590611636565b906040519161204383610176565b8252602082015290565b60ff6001612022565b9190916120638351611636565b93600091825b8481106120795750505050505090565b816000528360205282604060002006908160081c916120988389612321565b519260ff82169360019485808093831c1614928315936120db575b5050506120d257906120c683928a612571565b019301935b9392612069565b509301936120cb565b8293506120e8908d612321565b51901c16148338806120b3565b60041b90610ff060f083169216820361055157565b600954811015612163578060041c906008548210156116c45760ff61215d600f61ffff9460086000527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee3015493166120f5565b161c1690565b60046040517f4e23d035000000000000000000000000000000000000000000000000000000008152fd5b600554811015612163578060041c906004548210156116c45760ff61215d600f61ffff9460046000527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b015493166120f5565b61ffff80806001840116921682106121f6575090565b905090565b60095481101561216357600f8160041c911660ff61222b61ffff8083612220866120f5565b161b199516926120f5565b161b906008548110156116c4577ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee301918254161790600860005255565b60055481101561216357600f8160041c911660ff61228d61ffff8083612220866120f5565b161b906004548110156116c4577f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b01918254161790600460005255565b909161186d9493926040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000602082019260601b1682526014815261230e81610176565b5190206001830154925460801c92612611565b80518210156116c45760209160051b010190565b60019160ff61234984938360081c90612321565b5191161c161490565b9161186d9391612361936126f3565b9190916127c8565b906000805b83518210156124bc576001906123848386612321565b517f55555555555555555555555555555555555555555555555555555555555555558082851c169116017f3333333333333333333333333333333333333333333333333333333333333333808260021c169116017f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f808260041c169116017eff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff808260081c169116017dffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff808260101c169116017bffffffff00000000ffffffff00000000ffffffff00000000ffffffff808260201c1691160177ffffffffffffffff0000000000000000ffffffffffffffff808260401c169116016fffffffffffffffffffffffffffffffff8160801c9116010191019061236e565b925050565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818111610551576003900481039081116105515790565b9061250582612951565b83018093116105515761251790612951565b8060011b907f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81160361055157806001016001116105515760019083010180921161055157612565906124c1565b808210156121f6575090565b90612594908060081c90600160ff6125898487612321565b5192161b1792612321565b52565b6125e67fffffffff000000000000000000000000000000000000000000000000000000009162ff00ff63ff00ff008260081b169160081c161761ffff63ffff00008260101b169160101c161790565b60e01b1690565b90612594908060081c90600160ff6126058487612321565b5192161b191692612321565b939294919094808210156126e857909291906000905b8282106126375750505050501490565b9091929395600190819081808a161480156126dd575b1561269e5761265d8587896116b4565b356000526020527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6040600020985b821c9301811c01920190939291612627565b6126a98587896116b4565b35906000526020527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60406000209861268c565b5083828a011461264d565b505050505050600090565b9291907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083116127835791608094939160ff602094604051948552168484015260408301526060820152600093849182805260015afa1561277657815173ffffffffffffffffffffffffffffffffffffffff811615612770579190565b50600190565b50604051903d90823e3d90fd5b50505050600090600390565b6005111561279957565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6127d18161278f565b806127d95750565b6127e28161278f565b60018103612849576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606490fd5b6128528161278f565b600281036128b9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606490fd5b806128c560039261278f565b146128cc57565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608490fd5b806000918160801c80612a12575b508060401c80612a05575b508060201c806129f8575b508060101c806129eb575b508060081c806129de575b508060041c806129d1575b508060021c806129c4575b5060011c6129ba575b6001821b101561186d5760010190565b90600101906129aa565b60029150920191386129a1565b6004915092019138612996565b600891509201913861298b565b6010915092019138612980565b6020915092019138612975565b604091509201913861296a565b6080935090503861295f565b63ffffffff808211612a345761186d9116612a88565b60046040517fe809999a000000000000000000000000000000000000000000000000000000008152fd5b90600263ffffffff8093160191821161055157565b90600163ffffffff8093160191821161055157565b63ffffffff8116603f8111612ad5575060405160fa9190911b7ffc0000000000000000000000000000000000000000000000000000000000000016602082015261186d816021810161072a565b613fff8111612b4f575061186d612b17612b04612afd63fffffffc61072a9560021b16612a73565b61ffff1690565b60ff61ff008260081b169160081c161790565b604051928391602083017fffff00000000000000000000000000000000000000000000000000000000000060029260f01b1681520190565b633fffffff10612bd65761186d612b9e612b7463fffffffc61072a9460021b16612a5e565b62ff00ff63ff00ff008260081b169160081c161761ffff63ffff00008260101b169160101c161790565b604051928391602083017fffffffff0000000000000000000000000000000000000000000000000000000060049260e01b1681520190565b61186d612c0a61072a9262ff00ff63ff00ff008260081b169160081c161761ffff63ffff00008260101b169160101c161790565b604051928391602083017fffffffff000000000000000000000000000000000000000000000000000000006005927f0300000000000000000000000000000000000000000000000000000000000000835260e01b166001820152019056fea2646970667358221220c46c43127ee70fb5d31894dd32138d636a39b1aca030fef926ab751d1aefc58a64736f6c63430008190033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000029048b00000000000000000000000000000000000000000000000000000000000011c1000000000000000000000000000000000000000000000000000000000000005dacb0d61a25cb582707310607640e8c46a12c006b9b0b27861a4eac59e37da10700000000000000000000000000000000000000000000000000000000000011c2000000000000000000000000000000000000000000000000000000000000005dacb0d61a25cb582707310607640e8c46a12c006b9b0b27861a4eac59e37da107
-----Decoded View---------------
Arg [0] : _randaoCommitDelay (uint256): 128
Arg [1] : _randaoCommitExpiration (uint256): 6
Arg [2] : _minNumRequiredSignatures (uint256): 16
Arg [3] : _initialBeefyBlock (uint64): 2688139
Arg [4] : _initialValidatorSet (tuple): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]
Arg [5] : _nextValidatorSet (tuple): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]
-----Encoded View---------------
10 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000080
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000006
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000010
Arg [3] : 000000000000000000000000000000000000000000000000000000000029048b
Arg [4] : 00000000000000000000000000000000000000000000000000000000000011c1
Arg [5] : 000000000000000000000000000000000000000000000000000000000000005d
Arg [6] : acb0d61a25cb582707310607640e8c46a12c006b9b0b27861a4eac59e37da107
Arg [7] : 00000000000000000000000000000000000000000000000000000000000011c2
Arg [8] : 000000000000000000000000000000000000000000000000000000000000005d
Arg [9] : acb0d61a25cb582707310607640e8c46a12c006b9b0b27861a4eac59e37da107
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.