Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 10,836 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Submit Initial | 21451099 | 57 days ago | IN | 0 ETH | 0.00103227 | ||||
Submit Final | 21451098 | 57 days ago | IN | 0 ETH | 0.0034573 | ||||
Commit Prev Rand... | 21451096 | 57 days ago | IN | 0 ETH | 0.00036504 | ||||
Submit Initial | 21450966 | 57 days ago | IN | 0 ETH | 0.00119185 | ||||
Submit Final | 21450963 | 57 days ago | IN | 0 ETH | 0.0042421 | ||||
Commit Prev Rand... | 21450960 | 57 days ago | IN | 0 ETH | 0.00045432 | ||||
Submit Initial | 21450830 | 57 days ago | IN | 0 ETH | 0.00085164 | ||||
Submit Initial | 21450828 | 57 days ago | IN | 0 ETH | 0.00106023 | ||||
Submit Final | 21450826 | 57 days ago | IN | 0 ETH | 0.00375692 | ||||
Commit Prev Rand... | 21450823 | 57 days ago | IN | 0 ETH | 0.00042729 | ||||
Submit Initial | 21450693 | 57 days ago | IN | 0 ETH | 0.00088519 | ||||
Submit Final | 21450692 | 57 days ago | IN | 0 ETH | 0.00286334 | ||||
Commit Prev Rand... | 21450690 | 57 days ago | IN | 0 ETH | 0.00030587 | ||||
Submit Initial | 21450559 | 57 days ago | IN | 0 ETH | 0.00088793 | ||||
Submit Final | 21450556 | 57 days ago | IN | 0 ETH | 0.00281677 | ||||
Commit Prev Rand... | 21450554 | 57 days ago | IN | 0 ETH | 0.00032174 | ||||
Submit Initial | 21450424 | 57 days ago | IN | 0 ETH | 0.00084398 | ||||
Submit Final | 21450422 | 57 days ago | IN | 0 ETH | 0.00277367 | ||||
Commit Prev Rand... | 21450420 | 57 days ago | IN | 0 ETH | 0.0003072 | ||||
Submit Initial | 21450290 | 57 days ago | IN | 0 ETH | 0.00095409 | ||||
Submit Final | 21450289 | 57 days ago | IN | 0 ETH | 0.00300363 | ||||
Commit Prev Rand... | 21450287 | 57 days ago | IN | 0 ETH | 0.00033 | ||||
Submit Initial | 21450155 | 57 days ago | IN | 0 ETH | 0.00101301 | ||||
Submit Final | 21450154 | 57 days ago | IN | 0 ETH | 0.00322341 | ||||
Commit Prev Rand... | 21450152 | 57 days ago | IN | 0 ETH | 0.00031665 |
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 999999 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: 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); } } }
// 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]> 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]> // 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 // 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: 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; /** * @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; }
{ "optimizer": { "enabled": true, "runs": 999999 }, "evmVersion": "paris", "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"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
60e060405234801561001057600080fd5b506040516137fc3803806137fc83398101604081905261002f9161033d565b815161003c9060016103c5565b6001600160801b031681600001516001600160801b0316146100a45760405162461bcd60e51b815260206004820152601a60248201527f696e76616c69642d636f6e7374727563746f722d706172616d73000000000000604482015260640160405180910390fd5b608086905260a085905260c0849052600180546001600160401b0319166001600160401b038516179055815160208301516001600160801b03918216600160801b91831682021760028190556040850151600355610105929190041661018e565b8051805160049161011b91839160200190610236565b50602091820151600191909101558151908201516001600160801b03918216600160801b9183168202176006819055604084015160075561015f929190041661018e565b8051805160089161017591839160200190610236565b5060208201518160010155905050505050505050610443565b60408051808201909152606081526000602082015260006101b0601084610402565b156101bc5760016101bf565b60005b60ff166101cd601085610416565b6101d7919061042a565b90506040518060400160405280826001600160401b038111156101fc576101fc610296565b604051908082528060200260200182016040528015610225578160200160208202803683370190505b508152602001939093525090919050565b828054828255906000526020600020908101928215610271579160200282015b82811115610271578251825591602001919060010190610256565b5061027d929150610281565b5090565b5b8082111561027d5760008155600101610282565b634e487b7160e01b600052604160045260246000fd5b80516001600160801b03811681146102c357600080fd5b919050565b6000606082840312156102da57600080fd5b604051606081016001600160401b038111828210171561030a57634e487b7160e01b600052604160045260246000fd5b604052905080610319836102ac565b8152610327602084016102ac565b6020820152604083015160408201525092915050565b600080600080600080610140878903121561035757600080fd5b86516020880151604089015160608a015192985090965094506001600160401b038116811461038557600080fd5b925061039488608089016102c8565b91506103a38860e089016102c8565b90509295509295509295565b634e487b7160e01b600052601160045260246000fd5b6001600160801b038181168382160190808211156103e5576103e56103af565b5092915050565b634e487b7160e01b600052601260045260246000fd5b600082610411576104116103ec565b500690565b600082610425576104256103ec565b500490565b8082018082111561043d5761043d6103af565b92915050565b60805160a05160c05161336e61048e6000396000818161021c0152610fe501526000818161028c0152610b7901526000818161019301528181610b0d0152610b9f015261336e6000f3fe608060405234801561001057600080fd5b50600436106100f55760003560e01c806366ae69a011610097578063a77cf3d211610066578063a77cf3d214610274578063ad209a9b14610287578063bb51f1eb146102ae578063df0dd0d5146102c157600080fd5b806366ae69a0146101ea5780636f55bd32146102175780638ab81d131461023e578063a401662b1461025157600080fd5b806341c9634e116100d357806341c9634e14610177578063591d99ee1461018e5780635da57fe9146101b5578063623b223d146101d557600080fd5b80630a7c8faa146100fa5780632cdea71714610157578063366675131461016f575b600080fd5b6101217f6d6800000000000000000000000000000000000000000000000000000000000081565b6040517fffff00000000000000000000000000000000000000000000000000000000000090911681526020015b60405180910390f35b61015f61035c565b60405161014e9493929190612a13565b61015f6103f5565b61018060005481565b60405190815260200161014e565b6101807f000000000000000000000000000000000000000000000000000000000000000081565b6101c86101c3366004612aef565b61048c565b60405161014e9190612b3b565b6101e86101e3366004612ba9565b6104db565b005b6001546101fe9067ffffffffffffffff1681565b60405167ffffffffffffffff909116815260200161014e565b6101807f000000000000000000000000000000000000000000000000000000000000000081565b6101c861024c366004612c87565b610950565b61026461025f366004612cd3565b610a53565b604051901515815260200161014e565b6101e8610282366004612d26565b610a64565b6101807f000000000000000000000000000000000000000000000000000000000000000081565b6101e86102bc366004612d3f565b610c5e565b61031f6102cf366004612d26565b600a6020526000908152604090208054600182015460029092015467ffffffffffffffff82169263ffffffff6801000000000000000084048116936c010000000000000000000000009004169185565b6040805167ffffffffffffffff96909616865263ffffffff948516602087015292909316918401919091526060830152608082015260a00161014e565b6002805460035460408051600480546060602082028401810185529383018181526fffffffffffffffffffffffffffffffff80881698700100000000000000000000000000000000909804169694849284918401828280156103dd57602002820191906000526020600020905b8154815260200190600101908083116103c9575b50505050508152602001600182015481525050905084565b6006805460075460408051600880546060602082028401810185529383018181526fffffffffffffffffffffffffffffffff80881698700100000000000000000000000000000000909804169694849284918401828280156103dd57602002820191906000526020600020908154815260200190600101908083116103c95750505050508152602001600182015481525050905084565b6060828210156104c8576040517f5c85a0e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104d3848484611187565b949350505050565b60006104e68a611228565b8051906020012090506000610505338360009182526020526040902090565b9050610513818c8c8c61131b565b600080600660000160009054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff168d602001602081019061055d9190612dd2565b67ffffffffffffffff16036105785750600190506006610608565b600260000160009054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff168d60200160208101906105bf9190612dd2565b67ffffffffffffffff16036105d657506002610608565b6040517fc06789fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61061784848e8e858f8f611472565b60006106228e6116c9565b9050821561083f5760065461064a906fffffffffffffffffffffffffffffffff166001612e2b565b6fffffffffffffffffffffffffffffffff1661066c60808b0160608c01612dd2565b67ffffffffffffffff16146106ad576040517fc72c820000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006106cb826106bc8c611868565b805190602001208b8b8b611964565b905080610704576040517f128597bb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600680547001000000000000000000000000000000008082046fffffffffffffffffffffffffffffffff9081169091029116176002908155600754600355600880546004906107569082908490612973565b5060019182015491015550610773905060808b0160608c01612dd2565b600680547fffffffffffffffffffffffffffffffff000000000000000000000000000000001667ffffffffffffffff929092169190911790556107bc60a08b0160808c01612e54565b600680546fffffffffffffffffffffffffffffffff1663ffffffff929092167001000000000000000000000000000000000291909117905560a08a0180356007556108199061080e9060808d01612e54565b63ffffffff166119ee565b8051805160089161082f918391602001906129c3565b5060208201518160010155905050505b600081905561085160208f018f612e54565b63ffffffff16600160006101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550600a6000858152602001908152602001600020600080820160006101000a81549067ffffffffffffffff02191690556000820160086101000a81549063ffffffff021916905560008201600c6101000a81549063ffffffff02191690556001820160009055600282016000905550507fd95fe1258d152dc91c81b09380498adc76ed36a6079bcb2ed31eff622ae2d0f1818f60000160208101906109239190612e54565b6040805192835263ffffffff90911660208301520160405180910390a15050505050505050505050505050565b60606000600a600061096c338860009182526020526040902090565b81526020019081526020016000209050838360405160200161098f929190612e7a565b604051602081830303815290604052805190602001208160020154146109e1576040517f6768c0aa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610a4a816001015485858080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050855463ffffffff6c0100000000000000000000000082048116935068010000000000000000909104169050611a97565b95945050505050565b6000610a4a60005486868686611964565b3360009081526020829052604081206000818152600a6020526040812080549293509167ffffffffffffffff169003610ac9576040517f6686db6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600181015415610b05576040517fe31d900500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8054610b3c907f00000000000000000000000000000000000000000000000000000000000000009067ffffffffffffffff16612ebc565b431015610b75576040517fc77c194900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80547f000000000000000000000000000000000000000000000000000000000000000090610bce907f00000000000000000000000000000000000000000000000000000000000000009067ffffffffffffffff16612ebc565b610bd89190612ebc565b431115610c53576000828152600a602052604080822080547fffffffffffffffffffffffffffffffff00000000000000000000000000000000168155600181018390556002019190915580517f40d3544700000000000000000000000000000000000000000000000000000000815290519081900360040190fd5b446001909101555050565b60015467ffffffffffffffff16610c786020860186612e54565b63ffffffff1611610cb5576040517f3d618e5000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025460009081906fffffffffffffffffffffffffffffffff16610cdf6040880160208901612dd2565b67ffffffffffffffff1603610d2857610cfd60046060850135611b46565b9050610d1f6060840135610d1661ffff84166001611bcd565b60049190611bec565b60029150610d92565b6006546fffffffffffffffffffffffffffffffff16610d4d6040880160208901612dd2565b67ffffffffffffffff16036105d657610d6b60086060850135611b46565b9050610d8d6060840135610d8461ffff84166001611bcd565b60089190611bec565b600691505b610dbd82610da660a0860160808701612ecf565b6060860135610db860a0880188612f05565b611cb3565b1580610e065750610e048585808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152505050506060850135611d6a565b155b15610e3d576040517fe00153fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610e4887611228565b80516020909101209050610e6260a0850160808601612ecf565b73ffffffffffffffffffffffffffffffffffffffff16610e9882610e896020880188612f6d565b87602001358860400135611daf565b73ffffffffffffffffffffffffffffffffffffffff1614610ee5576040517f8baa579f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8254610f169070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16611dd7565b610f52878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250611dfa92505050565b1015610f8a576040517fee3e74af00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160a0810182524367ffffffffffffffff1681528454700100000000000000000000000000000000900463ffffffff811660208301529091820190611009906fffffffffffffffffffffffffffffffff1661ffff86167f000000000000000000000000000000000000000000000000000000000000000061206a565b63ffffffff16815260200160008152602001878760405160200161102e929190612e7a565b60405160208183030381529060405280519060200120815250600a600061105f338560009182526020526040902090565b8152602080820192909252604090810160002083518154858501519386015163ffffffff9081166c01000000000000000000000000027fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff9190951668010000000000000000027fffffffffffffffffffffffffffffffffffffffff00000000000000000000000090921667ffffffffffffffff909316929092171716919091178155606083015160018201556080909201516002909201919091557fbee983fc706c692efb9b0240bddc5666c010a53af55ed5fb42d226e7e429386990339061114a908a018a612e54565b6040805173ffffffffffffffffffffffffffffffffffffffff909316835263ffffffff90911660208301520160405180910390a150505050505050565b606060006101006111998460ff612ebc565b6111a39190612fbf565b90508067ffffffffffffffff8111156111be576111be612fd3565b6040519080825280602002602001820160405280156111e7578160200160208202803683370190505b50915060005b8481101561121f576112178387878481811061120b5761120b613002565b905060200201356120c3565b6001016111ed565b50509392505050565b606061123f61123a6040840184612f05565b61211b565b61127661124f6020850185612e54565b600881811c62ff00ff1663ff00ff009290911b9190911617601081811c91901b1760e01b90565b6112f36112896040860160208701612dd2565b600065ff000000ff00600883811b91821664ff000000ff9185901c91821617601090811b67ff000000ff0000009390931666ff000000ff00009290921691909117901c17602081811b6bffffffffffffffff000000001691901c63ffffffff161760c01b92915050565b60405160200161130593929190613061565b6040516020818303038152906040529050919050565b6000848152600a602052604081208054909167ffffffffffffffff9091169003611371576040517f6686db6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600101546000036113af576040517f78ef3a4700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60015467ffffffffffffffff166113c96020860186612e54565b63ffffffff1611611406576040517f3d618e5000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8282604051602001611419929190612e7a565b6040516020818303038152906040528051906020012081600201541461146b576040517f6768c0aa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b6000868152600a6020526040902080546c01000000000000000000000000900463ffffffff168281146114d1576040517f1f1711da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061153e8360010154898980806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250508a5487925070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff169050611a97565b905060005b848110156116bc573686868381811061155e5761155e613002565b905060200281019061157091906130c5565b9050611580838260600135611d6a565b6115b6576040517fe00153fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6115dc886115ca60a0840160808501612ecf565b6060840135610db860a0860186612f05565b611612576040517fe00153fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61162260a0820160808301612ecf565b73ffffffffffffffffffffffffffffffffffffffff166116588d6116496020850185612f6d565b84602001358560400135611daf565b73ffffffffffffffffffffffffffffffffffffffff16146116a5576040517f8baa579f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6116b383826060013561222a565b50600101611543565b5050505050505050505050565b6000805b6116da6040840184612f05565b9050811015611835577f6d680000000000000000000000000000000000000000000000000000000000006117116040850185612f05565b8381811061172157611721613002565b90506020028101906117339190613103565b611741906020810190613137565b7fffff000000000000000000000000000000000000000000000000000000000000160361182d576117756040840184612f05565b8281811061178557611785613002565b90506020028101906117979190613103565b6117a5906020810190613179565b90506020146117e0576040517f7df9c48600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6117ed6040840184612f05565b828181106117fd576117fd613002565b905060200281019061180f9190613103565b61181d906020810190613179565b611826916131de565b9392505050565b6001016116cd565b506040517f484ab7df00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606061188061187a6020840184612f6d565b60f81b90565b61189361124f6040850160208601612e54565b60408401356118ab6112896080870160608801612dd2565b6118be61124f60a0880160808901612e54565b6040517fff0000000000000000000000000000000000000000000000000000000000000090951660208601527fffffffff00000000000000000000000000000000000000000000000000000000938416602186015260258501929092527fffffffffffffffff00000000000000000000000000000000000000000000000016604584015216604d82015260a0830135605182015260c08301356071820152609101611305565b60006101008311156119a2576040517f5e862a8a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8460005b848110156119e1576119d7828787848181106119c4576119c4613002565b905060200201358387901c60011661225f565b91506001016119a6565b5090951495945050505050565b6040805180820190915260608152600060208201526000611a1060108461321a565b15611a1c576001611a1f565b60005b60ff16611a2d601085612fbf565b611a379190612ebc565b905060405180604001604052808267ffffffffffffffff811115611a5d57611a5d612fd3565b604051908082528060200260200182016040528015611a86578160200160208202803683370190505b508152602001939093525090919050565b6060835167ffffffffffffffff811115611ab357611ab3612fd3565b604051908082528060200260200182016040528015611adc578160200160208202803683370190505b5090506000805b84821015611b3c576000878152602082905260409020849006611b068782611d6a565b1580611b175750611b178482611d6a565b15611b255750600101611ae3565b611b2f84826120c3565b5060019182019101611ae3565b5050949350505050565b600082600101548210611b85576040517f4e23d03500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600482901c600f8316611b9981601061322e565b60ff16856000018381548110611bb157611bb1613002565b9060005260206000200154901c61ffff16925050505b92915050565b600082820161ffff80851690821610156118265761ffff915050611bc7565b82600101548210611c29576040517f4e23d03500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600482901c600f83166000611c3f82601061322e565b60ff1661ffff901b1990506000826010611c59919061322e565b60ff168561ffff16901b90508082886000018681548110611c7c57611c7c613002565b90600052602060002001541617876000018581548110611c9e57611c9e613002565b60009182526020909120015550505050505050565b6040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606086901b1660208201526000908190603401604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0018152919052805160209091012060018801548854919250611d5f918390889070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16888861228c565b979650505050505050565b600080600883901c9050611da083858381518110611d8a57611d8a613002565b60200260200101516122b990919063ffffffff16565b60ff1660011491505092915050565b6000806000611dc0878787876122c3565b91509150611dcd816123b2565b5095945050505050565b60006003611de660018461324a565b611df09190612fbf565b611bc7908361324a565b600080805b8351811015612063576000848281518110611e1c57611e1c613002565b602002602001015190507f5555555555555555555555555555555555555555555555555555555555555555600182901c167f555555555555555555555555555555555555555555555555555555555555555582160190507f3333333333333333333333333333333333333333333333333333333333333333600282901c167f333333333333333333333333333333333333333333333333333333333333333382160190507f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f600482901c167f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f82160190507eff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff600882901c167eff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff82160190507dffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff601082901c167dffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff82160190507bffffffff00000000ffffffff00000000ffffffff00000000ffffffff602082901c167bffffffff00000000ffffffff00000000ffffffff00000000ffffffff821601905077ffffffffffffffff0000000000000000ffffffffffffffff604082901c1677ffffffffffffffff0000000000000000ffffffffffffffff82160190506fffffffffffffffffffffffffffffffff608082901c166fffffffffffffffffffffffffffffffff82160190508083019250508080600101915050611dff565b5092915050565b60008161207885600161256d565b6120829082612ebc565b905061208f84600161256d565b61209a90600261325d565b6120a5906001612ebc565b6120af9082612ebc565b9050610a4a816120be87611dd7565b6125ac565b6000600882901c90506120f8828483815181106120e2576120e2613002565b60200260200101516125c290919063ffffffff16565b83828151811061210a5761210a613002565b602002602001018181525050505050565b60606000612128836125cf565b905060005b83811015612222578185858381811061214857612148613002565b905060200281019061215a9190613103565b612168906020810190613137565b6121a487878581811061217d5761217d613002565b905060200281019061218f9190613103565b61219d906020810190613179565b90506125cf565b8787858181106121b6576121b6613002565b90506020028101906121c89190613103565b6121d6906020810190613179565b6040516020016121ea959493929190613274565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052915060010161212d565b509392505050565b6000600882901c90506120f88284838151811061224957612249613002565b602002602001015161261890919063ffffffff16565b600081801561227557836000528460205261227e565b84600052836020525b505060406000209392505050565b600083851061229d575060006122af565b6122aa8686868686612626565b871490505b9695505050505050565b60ff161c60011690565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156122fa57506000905060036123a9565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa15801561234e573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166123a2576000600192509250506123a9565b9150600090505b94509492505050565b60008160048111156123c6576123c66132ca565b036123ce5750565b60018160048111156123e2576123e26132ca565b0361244e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e6174757265000000000000000060448201526064015b60405180910390fd5b6002816004811115612462576124626132ca565b036124c9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401612445565b60038160048111156124dd576124dd6132ca565b0361256a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401612445565b50565b600080612579846126ee565b905061258483612782565b8015612593575083816001901b105b61259e5760006125a1565b60015b60ff16019392505050565b60008183106125bb5781611826565b5090919050565b600160ff919091161b1790565b606063ffffffff82111561260f576040517fe809999a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611bc7826127af565b600160ff919091161b191690565b600085815b838110156126e357866001166001148061264757508587600101145b1561267f5761267885858381811061266157612661613002565b905060200201358360009182526020526040902090565b91506126ae565b6126ab8286868481811061269557612695613002565b9050602002013560009182526020526040902090565b91505b600196871c967fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909601861c8601950161262b565b509695505050505050565b600080608083901c1561270357608092831c92015b604083901c1561271557604092831c92015b602083901c1561272757602092831c92015b601083901c1561273957601092831c92015b600883901c1561274b57600892831c92015b600483901c1561275d57600492831c92015b600283901c1561276f57600292831c92015b600183901c15611bc75760010192915050565b60006002826003811115612798576127986132ca565b6127a291906132f9565b60ff166001149050919050565b6060603f8263ffffffff16116127f6576040517ffc0000000000000000000000000000000000000000000000000000000000000060fa84901b166020820152602101611305565b613fff8263ffffffff161161286d5761283261281e6403fffffffc600285901b16600161331b565b600881811b62ffff001691901c60ff161790565b604051602001611305919060f09190911b7fffff00000000000000000000000000000000000000000000000000000000000016815260020190565b633fffffff8263ffffffff16116128f7576128bc60028363ffffffff16901b6002612898919061331b565b600881811c62ff00ff1663ff00ff009290911b9190911617601081811c91901b1790565b604051602001611305919060e09190911b7fffffffff0000000000000000000000000000000000000000000000000000000016815260040190565b6040517f030000000000000000000000000000000000000000000000000000000000000060208201527fffffffff00000000000000000000000000000000000000000000000000000000600884811c62ff00ff1663ff00ff009186901b9190911617601081811c91901b1760e01b166021820152602501611305565b8280548282559060005260206000209081019282156129b35760005260206000209182015b828111156129b3578254825591600101919060010190612998565b506129bf9291506129fe565b5090565b8280548282559060005260206000209081019282156129b3579160200282015b828111156129b35782518255916020019190600101906129e3565b5b808211156129bf57600081556001016129ff565b60006fffffffffffffffffffffffffffffffff8087168352602081871660208501528560408501526080606085015260c08401915084516040608086015282815180855260e087019150602083019450600092505b80831015612a885784518252938301936001929092019190830190612a68565b50602087015160a08701528094505050505095945050505050565b60008083601f840112612ab557600080fd5b50813567ffffffffffffffff811115612acd57600080fd5b6020830191508360208260051b8501011115612ae857600080fd5b9250929050565b600080600060408486031215612b0457600080fd5b833567ffffffffffffffff811115612b1b57600080fd5b612b2786828701612aa3565b909790965060209590950135949350505050565b6020808252825182820181905260009190848201906040850190845b81811015612b7357835183529284019291840191600101612b57565b50909695505050505050565b600060608284031215612b9157600080fd5b50919050565b600060e08284031215612b9157600080fd5b60008060008060008060008060006101808a8c031215612bc857600080fd5b893567ffffffffffffffff80821115612be057600080fd5b612bec8d838e01612b7f565b9a5060208c0135915080821115612c0257600080fd5b612c0e8d838e01612aa3565b909a50985060408c0135915080821115612c2757600080fd5b612c338d838e01612aa3565b9098509650869150612c488d60608e01612b97565b95506101408c0135915080821115612c5f57600080fd5b50612c6c8c828d01612aa3565b9a9d999c50979a969995989497966101600135949350505050565b600080600060408486031215612c9c57600080fd5b83359250602084013567ffffffffffffffff811115612cba57600080fd5b612cc686828701612aa3565b9497909650939450505050565b60008060008060608587031215612ce957600080fd5b84359350602085013567ffffffffffffffff811115612d0757600080fd5b612d1387828801612aa3565b9598909750949560400135949350505050565b600060208284031215612d3857600080fd5b5035919050565b60008060008060608587031215612d5557600080fd5b843567ffffffffffffffff80821115612d6d57600080fd5b612d7988838901612b7f565b95506020870135915080821115612d8f57600080fd5b612d9b88838901612aa3565b90955093506040870135915080821115612db457600080fd5b50850160c08188031215612dc757600080fd5b939692955090935050565b600060208284031215612de457600080fd5b813567ffffffffffffffff8116811461182657600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6fffffffffffffffffffffffffffffffff81811683821601908082111561206357612063612dfc565b600060208284031215612e6657600080fd5b813563ffffffff8116811461182657600080fd5b60007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831115612ea957600080fd5b8260051b80858437919091019392505050565b80820180821115611bc757611bc7612dfc565b600060208284031215612ee157600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461182657600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612f3a57600080fd5b83018035915067ffffffffffffffff821115612f5557600080fd5b6020019150600581901b3603821315612ae857600080fd5b600060208284031215612f7f57600080fd5b813560ff8116811461182657600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082612fce57612fce612f90565b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6000815160005b818110156130525760208185018101518683015201613038565b50600093019283525090919050565b600061306d8286613031565b7fffffffff0000000000000000000000000000000000000000000000000000000094909416845250507fffffffffffffffff000000000000000000000000000000000000000000000000166004820152600c01919050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff418336030181126130f957600080fd5b9190910192915050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc18336030181126130f957600080fd5b60006020828403121561314957600080fd5b81357fffff0000000000000000000000000000000000000000000000000000000000008116811461182657600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126131ae57600080fd5b83018035915067ffffffffffffffff8211156131c957600080fd5b602001915036819003821315612ae857600080fd5b80356020831015611bc7577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602084900360031b1b1692915050565b60008261322957613229612f90565b500690565b60ff818116838216029081169081811461206357612063612dfc565b81810381811115611bc757611bc7612dfc565b8082028115828204841417611bc757611bc7612dfc565b60006132808288613031565b7fffff000000000000000000000000000000000000000000000000000000000000871681526132b26002820187613031565b90508385823760009301928352509095945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600060ff83168061330c5761330c612f90565b8060ff84160691505092915050565b63ffffffff81811683821601908082111561206357612063612dfc56fea2646970667358221220d200b88b1fbd76940c01aeea4316095882bf04d47f9383da64dca480e6080f3a64736f6c6343000819003300000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000019591900000000000000000000000000000000000000000000000000000000000002de0000000000000000000000000000000000000000000000000000000000000095fa59503298e8233afb850f7dd29653d1f96d1fcbc5a8693f2aabeff99db2216200000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000000942b13c7e8b09f9135f3a8f26b5cd66107c2d65de8765ca685d144c37f3661bc55
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106100f55760003560e01c806366ae69a011610097578063a77cf3d211610066578063a77cf3d214610274578063ad209a9b14610287578063bb51f1eb146102ae578063df0dd0d5146102c157600080fd5b806366ae69a0146101ea5780636f55bd32146102175780638ab81d131461023e578063a401662b1461025157600080fd5b806341c9634e116100d357806341c9634e14610177578063591d99ee1461018e5780635da57fe9146101b5578063623b223d146101d557600080fd5b80630a7c8faa146100fa5780632cdea71714610157578063366675131461016f575b600080fd5b6101217f6d6800000000000000000000000000000000000000000000000000000000000081565b6040517fffff00000000000000000000000000000000000000000000000000000000000090911681526020015b60405180910390f35b61015f61035c565b60405161014e9493929190612a13565b61015f6103f5565b61018060005481565b60405190815260200161014e565b6101807f000000000000000000000000000000000000000000000000000000000000008081565b6101c86101c3366004612aef565b61048c565b60405161014e9190612b3b565b6101e86101e3366004612ba9565b6104db565b005b6001546101fe9067ffffffffffffffff1681565b60405167ffffffffffffffff909116815260200161014e565b6101807f000000000000000000000000000000000000000000000000000000000000000a81565b6101c861024c366004612c87565b610950565b61026461025f366004612cd3565b610a53565b604051901515815260200161014e565b6101e8610282366004612d26565b610a64565b6101807f000000000000000000000000000000000000000000000000000000000000001881565b6101e86102bc366004612d3f565b610c5e565b61031f6102cf366004612d26565b600a6020526000908152604090208054600182015460029092015467ffffffffffffffff82169263ffffffff6801000000000000000084048116936c010000000000000000000000009004169185565b6040805167ffffffffffffffff96909616865263ffffffff948516602087015292909316918401919091526060830152608082015260a00161014e565b6002805460035460408051600480546060602082028401810185529383018181526fffffffffffffffffffffffffffffffff80881698700100000000000000000000000000000000909804169694849284918401828280156103dd57602002820191906000526020600020905b8154815260200190600101908083116103c9575b50505050508152602001600182015481525050905084565b6006805460075460408051600880546060602082028401810185529383018181526fffffffffffffffffffffffffffffffff80881698700100000000000000000000000000000000909804169694849284918401828280156103dd57602002820191906000526020600020908154815260200190600101908083116103c95750505050508152602001600182015481525050905084565b6060828210156104c8576040517f5c85a0e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104d3848484611187565b949350505050565b60006104e68a611228565b8051906020012090506000610505338360009182526020526040902090565b9050610513818c8c8c61131b565b600080600660000160009054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff168d602001602081019061055d9190612dd2565b67ffffffffffffffff16036105785750600190506006610608565b600260000160009054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff168d60200160208101906105bf9190612dd2565b67ffffffffffffffff16036105d657506002610608565b6040517fc06789fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61061784848e8e858f8f611472565b60006106228e6116c9565b9050821561083f5760065461064a906fffffffffffffffffffffffffffffffff166001612e2b565b6fffffffffffffffffffffffffffffffff1661066c60808b0160608c01612dd2565b67ffffffffffffffff16146106ad576040517fc72c820000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006106cb826106bc8c611868565b805190602001208b8b8b611964565b905080610704576040517f128597bb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600680547001000000000000000000000000000000008082046fffffffffffffffffffffffffffffffff9081169091029116176002908155600754600355600880546004906107569082908490612973565b5060019182015491015550610773905060808b0160608c01612dd2565b600680547fffffffffffffffffffffffffffffffff000000000000000000000000000000001667ffffffffffffffff929092169190911790556107bc60a08b0160808c01612e54565b600680546fffffffffffffffffffffffffffffffff1663ffffffff929092167001000000000000000000000000000000000291909117905560a08a0180356007556108199061080e9060808d01612e54565b63ffffffff166119ee565b8051805160089161082f918391602001906129c3565b5060208201518160010155905050505b600081905561085160208f018f612e54565b63ffffffff16600160006101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550600a6000858152602001908152602001600020600080820160006101000a81549067ffffffffffffffff02191690556000820160086101000a81549063ffffffff021916905560008201600c6101000a81549063ffffffff02191690556001820160009055600282016000905550507fd95fe1258d152dc91c81b09380498adc76ed36a6079bcb2ed31eff622ae2d0f1818f60000160208101906109239190612e54565b6040805192835263ffffffff90911660208301520160405180910390a15050505050505050505050505050565b60606000600a600061096c338860009182526020526040902090565b81526020019081526020016000209050838360405160200161098f929190612e7a565b604051602081830303815290604052805190602001208160020154146109e1576040517f6768c0aa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610a4a816001015485858080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050855463ffffffff6c0100000000000000000000000082048116935068010000000000000000909104169050611a97565b95945050505050565b6000610a4a60005486868686611964565b3360009081526020829052604081206000818152600a6020526040812080549293509167ffffffffffffffff169003610ac9576040517f6686db6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600181015415610b05576040517fe31d900500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8054610b3c907f00000000000000000000000000000000000000000000000000000000000000809067ffffffffffffffff16612ebc565b431015610b75576040517fc77c194900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80547f000000000000000000000000000000000000000000000000000000000000001890610bce907f00000000000000000000000000000000000000000000000000000000000000809067ffffffffffffffff16612ebc565b610bd89190612ebc565b431115610c53576000828152600a602052604080822080547fffffffffffffffffffffffffffffffff00000000000000000000000000000000168155600181018390556002019190915580517f40d3544700000000000000000000000000000000000000000000000000000000815290519081900360040190fd5b446001909101555050565b60015467ffffffffffffffff16610c786020860186612e54565b63ffffffff1611610cb5576040517f3d618e5000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025460009081906fffffffffffffffffffffffffffffffff16610cdf6040880160208901612dd2565b67ffffffffffffffff1603610d2857610cfd60046060850135611b46565b9050610d1f6060840135610d1661ffff84166001611bcd565b60049190611bec565b60029150610d92565b6006546fffffffffffffffffffffffffffffffff16610d4d6040880160208901612dd2565b67ffffffffffffffff16036105d657610d6b60086060850135611b46565b9050610d8d6060840135610d8461ffff84166001611bcd565b60089190611bec565b600691505b610dbd82610da660a0860160808701612ecf565b6060860135610db860a0880188612f05565b611cb3565b1580610e065750610e048585808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152505050506060850135611d6a565b155b15610e3d576040517fe00153fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610e4887611228565b80516020909101209050610e6260a0850160808601612ecf565b73ffffffffffffffffffffffffffffffffffffffff16610e9882610e896020880188612f6d565b87602001358860400135611daf565b73ffffffffffffffffffffffffffffffffffffffff1614610ee5576040517f8baa579f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8254610f169070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16611dd7565b610f52878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250611dfa92505050565b1015610f8a576040517fee3e74af00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160a0810182524367ffffffffffffffff1681528454700100000000000000000000000000000000900463ffffffff811660208301529091820190611009906fffffffffffffffffffffffffffffffff1661ffff86167f000000000000000000000000000000000000000000000000000000000000000a61206a565b63ffffffff16815260200160008152602001878760405160200161102e929190612e7a565b60405160208183030381529060405280519060200120815250600a600061105f338560009182526020526040902090565b8152602080820192909252604090810160002083518154858501519386015163ffffffff9081166c01000000000000000000000000027fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff9190951668010000000000000000027fffffffffffffffffffffffffffffffffffffffff00000000000000000000000090921667ffffffffffffffff909316929092171716919091178155606083015160018201556080909201516002909201919091557fbee983fc706c692efb9b0240bddc5666c010a53af55ed5fb42d226e7e429386990339061114a908a018a612e54565b6040805173ffffffffffffffffffffffffffffffffffffffff909316835263ffffffff90911660208301520160405180910390a150505050505050565b606060006101006111998460ff612ebc565b6111a39190612fbf565b90508067ffffffffffffffff8111156111be576111be612fd3565b6040519080825280602002602001820160405280156111e7578160200160208202803683370190505b50915060005b8481101561121f576112178387878481811061120b5761120b613002565b905060200201356120c3565b6001016111ed565b50509392505050565b606061123f61123a6040840184612f05565b61211b565b61127661124f6020850185612e54565b600881811c62ff00ff1663ff00ff009290911b9190911617601081811c91901b1760e01b90565b6112f36112896040860160208701612dd2565b600065ff000000ff00600883811b91821664ff000000ff9185901c91821617601090811b67ff000000ff0000009390931666ff000000ff00009290921691909117901c17602081811b6bffffffffffffffff000000001691901c63ffffffff161760c01b92915050565b60405160200161130593929190613061565b6040516020818303038152906040529050919050565b6000848152600a602052604081208054909167ffffffffffffffff9091169003611371576040517f6686db6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600101546000036113af576040517f78ef3a4700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60015467ffffffffffffffff166113c96020860186612e54565b63ffffffff1611611406576040517f3d618e5000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8282604051602001611419929190612e7a565b6040516020818303038152906040528051906020012081600201541461146b576040517f6768c0aa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b6000868152600a6020526040902080546c01000000000000000000000000900463ffffffff168281146114d1576040517f1f1711da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061153e8360010154898980806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250508a5487925070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff169050611a97565b905060005b848110156116bc573686868381811061155e5761155e613002565b905060200281019061157091906130c5565b9050611580838260600135611d6a565b6115b6576040517fe00153fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6115dc886115ca60a0840160808501612ecf565b6060840135610db860a0860186612f05565b611612576040517fe00153fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61162260a0820160808301612ecf565b73ffffffffffffffffffffffffffffffffffffffff166116588d6116496020850185612f6d565b84602001358560400135611daf565b73ffffffffffffffffffffffffffffffffffffffff16146116a5576040517f8baa579f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6116b383826060013561222a565b50600101611543565b5050505050505050505050565b6000805b6116da6040840184612f05565b9050811015611835577f6d680000000000000000000000000000000000000000000000000000000000006117116040850185612f05565b8381811061172157611721613002565b90506020028101906117339190613103565b611741906020810190613137565b7fffff000000000000000000000000000000000000000000000000000000000000160361182d576117756040840184612f05565b8281811061178557611785613002565b90506020028101906117979190613103565b6117a5906020810190613179565b90506020146117e0576040517f7df9c48600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6117ed6040840184612f05565b828181106117fd576117fd613002565b905060200281019061180f9190613103565b61181d906020810190613179565b611826916131de565b9392505050565b6001016116cd565b506040517f484ab7df00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606061188061187a6020840184612f6d565b60f81b90565b61189361124f6040850160208601612e54565b60408401356118ab6112896080870160608801612dd2565b6118be61124f60a0880160808901612e54565b6040517fff0000000000000000000000000000000000000000000000000000000000000090951660208601527fffffffff00000000000000000000000000000000000000000000000000000000938416602186015260258501929092527fffffffffffffffff00000000000000000000000000000000000000000000000016604584015216604d82015260a0830135605182015260c08301356071820152609101611305565b60006101008311156119a2576040517f5e862a8a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8460005b848110156119e1576119d7828787848181106119c4576119c4613002565b905060200201358387901c60011661225f565b91506001016119a6565b5090951495945050505050565b6040805180820190915260608152600060208201526000611a1060108461321a565b15611a1c576001611a1f565b60005b60ff16611a2d601085612fbf565b611a379190612ebc565b905060405180604001604052808267ffffffffffffffff811115611a5d57611a5d612fd3565b604051908082528060200260200182016040528015611a86578160200160208202803683370190505b508152602001939093525090919050565b6060835167ffffffffffffffff811115611ab357611ab3612fd3565b604051908082528060200260200182016040528015611adc578160200160208202803683370190505b5090506000805b84821015611b3c576000878152602082905260409020849006611b068782611d6a565b1580611b175750611b178482611d6a565b15611b255750600101611ae3565b611b2f84826120c3565b5060019182019101611ae3565b5050949350505050565b600082600101548210611b85576040517f4e23d03500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600482901c600f8316611b9981601061322e565b60ff16856000018381548110611bb157611bb1613002565b9060005260206000200154901c61ffff16925050505b92915050565b600082820161ffff80851690821610156118265761ffff915050611bc7565b82600101548210611c29576040517f4e23d03500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600482901c600f83166000611c3f82601061322e565b60ff1661ffff901b1990506000826010611c59919061322e565b60ff168561ffff16901b90508082886000018681548110611c7c57611c7c613002565b90600052602060002001541617876000018581548110611c9e57611c9e613002565b60009182526020909120015550505050505050565b6040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606086901b1660208201526000908190603401604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0018152919052805160209091012060018801548854919250611d5f918390889070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16888861228c565b979650505050505050565b600080600883901c9050611da083858381518110611d8a57611d8a613002565b60200260200101516122b990919063ffffffff16565b60ff1660011491505092915050565b6000806000611dc0878787876122c3565b91509150611dcd816123b2565b5095945050505050565b60006003611de660018461324a565b611df09190612fbf565b611bc7908361324a565b600080805b8351811015612063576000848281518110611e1c57611e1c613002565b602002602001015190507f5555555555555555555555555555555555555555555555555555555555555555600182901c167f555555555555555555555555555555555555555555555555555555555555555582160190507f3333333333333333333333333333333333333333333333333333333333333333600282901c167f333333333333333333333333333333333333333333333333333333333333333382160190507f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f600482901c167f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f82160190507eff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff600882901c167eff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff82160190507dffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff601082901c167dffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff82160190507bffffffff00000000ffffffff00000000ffffffff00000000ffffffff602082901c167bffffffff00000000ffffffff00000000ffffffff00000000ffffffff821601905077ffffffffffffffff0000000000000000ffffffffffffffff604082901c1677ffffffffffffffff0000000000000000ffffffffffffffff82160190506fffffffffffffffffffffffffffffffff608082901c166fffffffffffffffffffffffffffffffff82160190508083019250508080600101915050611dff565b5092915050565b60008161207885600161256d565b6120829082612ebc565b905061208f84600161256d565b61209a90600261325d565b6120a5906001612ebc565b6120af9082612ebc565b9050610a4a816120be87611dd7565b6125ac565b6000600882901c90506120f8828483815181106120e2576120e2613002565b60200260200101516125c290919063ffffffff16565b83828151811061210a5761210a613002565b602002602001018181525050505050565b60606000612128836125cf565b905060005b83811015612222578185858381811061214857612148613002565b905060200281019061215a9190613103565b612168906020810190613137565b6121a487878581811061217d5761217d613002565b905060200281019061218f9190613103565b61219d906020810190613179565b90506125cf565b8787858181106121b6576121b6613002565b90506020028101906121c89190613103565b6121d6906020810190613179565b6040516020016121ea959493929190613274565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052915060010161212d565b509392505050565b6000600882901c90506120f88284838151811061224957612249613002565b602002602001015161261890919063ffffffff16565b600081801561227557836000528460205261227e565b84600052836020525b505060406000209392505050565b600083851061229d575060006122af565b6122aa8686868686612626565b871490505b9695505050505050565b60ff161c60011690565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156122fa57506000905060036123a9565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa15801561234e573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166123a2576000600192509250506123a9565b9150600090505b94509492505050565b60008160048111156123c6576123c66132ca565b036123ce5750565b60018160048111156123e2576123e26132ca565b0361244e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e6174757265000000000000000060448201526064015b60405180910390fd5b6002816004811115612462576124626132ca565b036124c9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401612445565b60038160048111156124dd576124dd6132ca565b0361256a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401612445565b50565b600080612579846126ee565b905061258483612782565b8015612593575083816001901b105b61259e5760006125a1565b60015b60ff16019392505050565b60008183106125bb5781611826565b5090919050565b600160ff919091161b1790565b606063ffffffff82111561260f576040517fe809999a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611bc7826127af565b600160ff919091161b191690565b600085815b838110156126e357866001166001148061264757508587600101145b1561267f5761267885858381811061266157612661613002565b905060200201358360009182526020526040902090565b91506126ae565b6126ab8286868481811061269557612695613002565b9050602002013560009182526020526040902090565b91505b600196871c967fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909601861c8601950161262b565b509695505050505050565b600080608083901c1561270357608092831c92015b604083901c1561271557604092831c92015b602083901c1561272757602092831c92015b601083901c1561273957601092831c92015b600883901c1561274b57600892831c92015b600483901c1561275d57600492831c92015b600283901c1561276f57600292831c92015b600183901c15611bc75760010192915050565b60006002826003811115612798576127986132ca565b6127a291906132f9565b60ff166001149050919050565b6060603f8263ffffffff16116127f6576040517ffc0000000000000000000000000000000000000000000000000000000000000060fa84901b166020820152602101611305565b613fff8263ffffffff161161286d5761283261281e6403fffffffc600285901b16600161331b565b600881811b62ffff001691901c60ff161790565b604051602001611305919060f09190911b7fffff00000000000000000000000000000000000000000000000000000000000016815260020190565b633fffffff8263ffffffff16116128f7576128bc60028363ffffffff16901b6002612898919061331b565b600881811c62ff00ff1663ff00ff009290911b9190911617601081811c91901b1790565b604051602001611305919060e09190911b7fffffffff0000000000000000000000000000000000000000000000000000000016815260040190565b6040517f030000000000000000000000000000000000000000000000000000000000000060208201527fffffffff00000000000000000000000000000000000000000000000000000000600884811c62ff00ff1663ff00ff009186901b9190911617601081811c91901b1760e01b166021820152602501611305565b8280548282559060005260206000209081019282156129b35760005260206000209182015b828111156129b3578254825591600101919060010190612998565b506129bf9291506129fe565b5090565b8280548282559060005260206000209081019282156129b3579160200282015b828111156129b35782518255916020019190600101906129e3565b5b808211156129bf57600081556001016129ff565b60006fffffffffffffffffffffffffffffffff8087168352602081871660208501528560408501526080606085015260c08401915084516040608086015282815180855260e087019150602083019450600092505b80831015612a885784518252938301936001929092019190830190612a68565b50602087015160a08701528094505050505095945050505050565b60008083601f840112612ab557600080fd5b50813567ffffffffffffffff811115612acd57600080fd5b6020830191508360208260051b8501011115612ae857600080fd5b9250929050565b600080600060408486031215612b0457600080fd5b833567ffffffffffffffff811115612b1b57600080fd5b612b2786828701612aa3565b909790965060209590950135949350505050565b6020808252825182820181905260009190848201906040850190845b81811015612b7357835183529284019291840191600101612b57565b50909695505050505050565b600060608284031215612b9157600080fd5b50919050565b600060e08284031215612b9157600080fd5b60008060008060008060008060006101808a8c031215612bc857600080fd5b893567ffffffffffffffff80821115612be057600080fd5b612bec8d838e01612b7f565b9a5060208c0135915080821115612c0257600080fd5b612c0e8d838e01612aa3565b909a50985060408c0135915080821115612c2757600080fd5b612c338d838e01612aa3565b9098509650869150612c488d60608e01612b97565b95506101408c0135915080821115612c5f57600080fd5b50612c6c8c828d01612aa3565b9a9d999c50979a969995989497966101600135949350505050565b600080600060408486031215612c9c57600080fd5b83359250602084013567ffffffffffffffff811115612cba57600080fd5b612cc686828701612aa3565b9497909650939450505050565b60008060008060608587031215612ce957600080fd5b84359350602085013567ffffffffffffffff811115612d0757600080fd5b612d1387828801612aa3565b9598909750949560400135949350505050565b600060208284031215612d3857600080fd5b5035919050565b60008060008060608587031215612d5557600080fd5b843567ffffffffffffffff80821115612d6d57600080fd5b612d7988838901612b7f565b95506020870135915080821115612d8f57600080fd5b612d9b88838901612aa3565b90955093506040870135915080821115612db457600080fd5b50850160c08188031215612dc757600080fd5b939692955090935050565b600060208284031215612de457600080fd5b813567ffffffffffffffff8116811461182657600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6fffffffffffffffffffffffffffffffff81811683821601908082111561206357612063612dfc565b600060208284031215612e6657600080fd5b813563ffffffff8116811461182657600080fd5b60007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831115612ea957600080fd5b8260051b80858437919091019392505050565b80820180821115611bc757611bc7612dfc565b600060208284031215612ee157600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461182657600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612f3a57600080fd5b83018035915067ffffffffffffffff821115612f5557600080fd5b6020019150600581901b3603821315612ae857600080fd5b600060208284031215612f7f57600080fd5b813560ff8116811461182657600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082612fce57612fce612f90565b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6000815160005b818110156130525760208185018101518683015201613038565b50600093019283525090919050565b600061306d8286613031565b7fffffffff0000000000000000000000000000000000000000000000000000000094909416845250507fffffffffffffffff000000000000000000000000000000000000000000000000166004820152600c01919050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff418336030181126130f957600080fd5b9190910192915050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc18336030181126130f957600080fd5b60006020828403121561314957600080fd5b81357fffff0000000000000000000000000000000000000000000000000000000000008116811461182657600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126131ae57600080fd5b83018035915067ffffffffffffffff8211156131c957600080fd5b602001915036819003821315612ae857600080fd5b80356020831015611bc7577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602084900360031b1b1692915050565b60008261322957613229612f90565b500690565b60ff818116838216029081169081811461206357612063612dfc565b81810381811115611bc757611bc7612dfc565b8082028115828204841417611bc757611bc7612dfc565b60006132808288613031565b7fffff000000000000000000000000000000000000000000000000000000000000871681526132b26002820187613031565b90508385823760009301928352509095945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600060ff83168061330c5761330c612f90565b8060ff84160691505092915050565b63ffffffff81811683821601908082111561206357612063612dfc56fea2646970667358221220d200b88b1fbd76940c01aeea4316095882bf04d47f9383da64dca480e6080f3a64736f6c63430008190033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000019591900000000000000000000000000000000000000000000000000000000000002de0000000000000000000000000000000000000000000000000000000000000095fa59503298e8233afb850f7dd29653d1f96d1fcbc5a8693f2aabeff99db2216200000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000000942b13c7e8b09f9135f3a8f26b5cd66107c2d65de8765ca685d144c37f3661bc55
-----Decoded View---------------
Arg [0] : _randaoCommitDelay (uint256): 128
Arg [1] : _randaoCommitExpiration (uint256): 24
Arg [2] : _minNumRequiredSignatures (uint256): 10
Arg [3] : _initialBeefyBlock (uint64): 1661209
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] : 0000000000000000000000000000000000000000000000000000000000000018
Arg [2] : 000000000000000000000000000000000000000000000000000000000000000a
Arg [3] : 0000000000000000000000000000000000000000000000000000000000195919
Arg [4] : 00000000000000000000000000000000000000000000000000000000000002de
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000095
Arg [6] : fa59503298e8233afb850f7dd29653d1f96d1fcbc5a8693f2aabeff99db22162
Arg [7] : 00000000000000000000000000000000000000000000000000000000000002df
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000094
Arg [9] : 2b13c7e8b09f9135f3a8f26b5cd66107c2d65de8765ca685d144c37f3661bc55
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 31 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.