Contract 0x0421e7e93a5895bfffac037fb1c1bb4ac5508d05

Contract Overview

Balance:
0 DEV
Txn Hash Method
Block
From
To
Value [Txn Fee]
0x737c2b1248397f462ea0453c6cfdf0463d455e67c31132396d55cd67db460e9b0x6080604040279802023-03-28 0:44:4863 days 10 hrs ago0xfaae07bac050bee1efc1a589be6629c3775f3272 IN  Create: ProofChain0 DEV0.102841619854
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0x4db8b646d30a427001e9d94044b3dc9b8a60598df6902b5a0b794c04a0f62d3644468162023-05-30 11:34:122 mins ago 0x0421e7e93a5895bfffac037fb1c1bb4ac5508d050x237d022014e42b6757876c5d08fa435c8ba283fd0 DEV
0x4db8b646d30a427001e9d94044b3dc9b8a60598df6902b5a0b794c04a0f62d3644468162023-05-30 11:34:122 mins ago 0x19492a5019b30471aa8fa2c6d9d39c99b5cda20c0x0421e7e93a5895bfffac037fb1c1bb4ac5508d050 DEV
0xf8aba4b327a3da0885ae9429bf57c7ccb00d886f1baa9f813597e3813d702a5744468152023-05-30 11:34:002 mins ago 0x19492a5019b30471aa8fa2c6d9d39c99b5cda20c0x0421e7e93a5895bfffac037fb1c1bb4ac5508d050 DEV
0xbc9378927c9bff24aa25c047585ae5609f0f9a0a9d741b078f70bd00b3385cbb44468142023-05-30 11:33:482 mins ago 0x0421e7e93a5895bfffac037fb1c1bb4ac5508d050x237d022014e42b6757876c5d08fa435c8ba283fd0 DEV
0xbc9378927c9bff24aa25c047585ae5609f0f9a0a9d741b078f70bd00b3385cbb44468142023-05-30 11:33:482 mins ago 0x19492a5019b30471aa8fa2c6d9d39c99b5cda20c0x0421e7e93a5895bfffac037fb1c1bb4ac5508d050 DEV
0x30d4d8f2a553a8d50a527acacd890bee46bf5e0f831b1a2a19249be43e0b55ff44468142023-05-30 11:33:482 mins ago 0x0421e7e93a5895bfffac037fb1c1bb4ac5508d050x237d022014e42b6757876c5d08fa435c8ba283fd0 DEV
0x30d4d8f2a553a8d50a527acacd890bee46bf5e0f831b1a2a19249be43e0b55ff44468142023-05-30 11:33:482 mins ago 0x19492a5019b30471aa8fa2c6d9d39c99b5cda20c0x0421e7e93a5895bfffac037fb1c1bb4ac5508d050 DEV
0x83c1d292d54549effb0f61678c9bd2953d0c58ecba6b327cd2986f25c9884cf444468142023-05-30 11:33:482 mins ago 0x0421e7e93a5895bfffac037fb1c1bb4ac5508d050x237d022014e42b6757876c5d08fa435c8ba283fd0 DEV
0x83c1d292d54549effb0f61678c9bd2953d0c58ecba6b327cd2986f25c9884cf444468142023-05-30 11:33:482 mins ago 0x19492a5019b30471aa8fa2c6d9d39c99b5cda20c0x0421e7e93a5895bfffac037fb1c1bb4ac5508d050 DEV
0xfb0c870cad3c88d2a12b515dd5d51b7d9b7af62da8b696dd6e8b27d5df70955444468142023-05-30 11:33:482 mins ago 0x0421e7e93a5895bfffac037fb1c1bb4ac5508d050x237d022014e42b6757876c5d08fa435c8ba283fd0 DEV
0xfb0c870cad3c88d2a12b515dd5d51b7d9b7af62da8b696dd6e8b27d5df70955444468142023-05-30 11:33:482 mins ago 0x19492a5019b30471aa8fa2c6d9d39c99b5cda20c0x0421e7e93a5895bfffac037fb1c1bb4ac5508d050 DEV
0xc707fc74bf610681b3f0004527609055407abeac5b3b7a93b814d9ab30b708c744468142023-05-30 11:33:482 mins ago 0x0421e7e93a5895bfffac037fb1c1bb4ac5508d050x237d022014e42b6757876c5d08fa435c8ba283fd0 DEV
0xc707fc74bf610681b3f0004527609055407abeac5b3b7a93b814d9ab30b708c744468142023-05-30 11:33:482 mins ago 0x19492a5019b30471aa8fa2c6d9d39c99b5cda20c0x0421e7e93a5895bfffac037fb1c1bb4ac5508d050 DEV
0xcc13311bce2fafde4ad4d2537d7da0db6a35eeccc821201c7d04ea897a2f645344468132023-05-30 11:33:123 mins ago 0x0421e7e93a5895bfffac037fb1c1bb4ac5508d050x237d022014e42b6757876c5d08fa435c8ba283fd0 DEV
0xcc13311bce2fafde4ad4d2537d7da0db6a35eeccc821201c7d04ea897a2f645344468132023-05-30 11:33:123 mins ago 0x19492a5019b30471aa8fa2c6d9d39c99b5cda20c0x0421e7e93a5895bfffac037fb1c1bb4ac5508d050 DEV
0xaf5caa59414759fdcfec9534e18f3d5de1af1532bc5605cfafd0d5dbe900e7b444468082023-05-30 11:32:004 mins ago 0x19492a5019b30471aa8fa2c6d9d39c99b5cda20c0x0421e7e93a5895bfffac037fb1c1bb4ac5508d050 DEV
0x9b5b4e06fa06851de06ab40457091e06e5a021cd9776da6e783fa02f899f69e144468082023-05-30 11:32:004 mins ago 0x0421e7e93a5895bfffac037fb1c1bb4ac5508d050x237d022014e42b6757876c5d08fa435c8ba283fd0 DEV
0x9b5b4e06fa06851de06ab40457091e06e5a021cd9776da6e783fa02f899f69e144468082023-05-30 11:32:004 mins ago 0x19492a5019b30471aa8fa2c6d9d39c99b5cda20c0x0421e7e93a5895bfffac037fb1c1bb4ac5508d050 DEV
0x1c9734d967b7bd1cc52ceadadb9c9ca158a2286a50ae5d06308741bcef41912844467972023-05-30 11:29:187 mins ago 0x0421e7e93a5895bfffac037fb1c1bb4ac5508d050x237d022014e42b6757876c5d08fa435c8ba283fd0 DEV
0x1c9734d967b7bd1cc52ceadadb9c9ca158a2286a50ae5d06308741bcef41912844467972023-05-30 11:29:187 mins ago 0x19492a5019b30471aa8fa2c6d9d39c99b5cda20c0x0421e7e93a5895bfffac037fb1c1bb4ac5508d050 DEV
0x38ed08a8e682531fc6143b3eab05e44375f8dbffe8d2b34d87f4bc7b1a33c33f44467892023-05-30 11:27:129 mins ago 0x0421e7e93a5895bfffac037fb1c1bb4ac5508d050x237d022014e42b6757876c5d08fa435c8ba283fd0 DEV
0x38ed08a8e682531fc6143b3eab05e44375f8dbffe8d2b34d87f4bc7b1a33c33f44467892023-05-30 11:27:129 mins ago 0x19492a5019b30471aa8fa2c6d9d39c99b5cda20c0x0421e7e93a5895bfffac037fb1c1bb4ac5508d050 DEV
0xaf31f4ac3c4ce000e76b1a3a793dd72a2ae2961d591996154923747ec400da2c44467862023-05-30 11:26:3610 mins ago 0x0421e7e93a5895bfffac037fb1c1bb4ac5508d050x237d022014e42b6757876c5d08fa435c8ba283fd0 DEV
0xaf31f4ac3c4ce000e76b1a3a793dd72a2ae2961d591996154923747ec400da2c44467862023-05-30 11:26:3610 mins ago 0x19492a5019b30471aa8fa2c6d9d39c99b5cda20c0x0421e7e93a5895bfffac037fb1c1bb4ac5508d050 DEV
0xdba5a3839b01bc76284a9cc6ff5c2034d3a4bd50cf2657cad1bca2330118741b44467842023-05-30 11:26:1210 mins ago 0x19492a5019b30471aa8fa2c6d9d39c99b5cda20c0x0421e7e93a5895bfffac037fb1c1bb4ac5508d050 DEV
[ Download CSV Export 
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
ProofChain

Compiler Version
v0.8.13+commit.abaa5c0e

Optimization Enabled:
Yes with 1000000 runs

Other Settings:
default evmVersion
File 1 of 7 : ProofChain.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.13;

import "./IOperationalStaking.sol";
import "@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";

contract ProofChain is OwnableUpgradeable {
    using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;
    using EnumerableSetUpgradeable for EnumerableSetUpgradeable.Bytes32Set;

    IOperationalStaking _stakingInterface; // staking contract

    bytes32 public constant GOVERNANCE_ROLE = keccak256("GOVERNANCE_ROLE");
    bytes32 public constant BLOCK_SPECIMEN_PRODUCER_ROLE = keccak256("BLOCK_SPECIMEN_PRODUCER_ROLE");
    bytes32 public constant AUDITOR_ROLE = keccak256("AUDITOR_ROLE");
    uint256 private constant _DIVIDER = 10 ** 18; // 18 decimals used for scaling

    uint256 private _blockSpecimenQuorum; // The value is represented as a uint <= 10**18. The threshold value will later be divided by 10**18 to represent it as a percentage.  e.g.) 10**18 == 100%; 5 * 10**17 == 50%;
    uint256 private _secondsPerBlock; // average block time on the chain where the ProofChain is deployed
    uint128 private _blockSpecimenRewardAllocation; // the reward allocated per block hash
    uint128 private _bspRequiredStake; // how much a validator should have staked in order to run an operator
    uint64 private _blockSpecimenSessionDuration; // the length of a session in blocks
    uint64 private _minSubmissionsRequired; // min number of participants who submitted the agreed specimen hash in order for the quorum to be achieved

    EnumerableSetUpgradeable.Bytes32Set private _roleNames; // set of all role names, this is unused anymore

    EnumerableSetUpgradeable.AddressSet private _blockSpecimenProducers; // currently enabled block specimen producer operators
    EnumerableSetUpgradeable.AddressSet private _governors; // governor operators
    EnumerableSetUpgradeable.AddressSet private _auditors; // auditor operators

    mapping(address => uint128) public validatorIDs; // maps an operator address to validatorId
    mapping(uint128 => EnumerableSetUpgradeable.AddressSet) private _validatorOperators; // operator addresses that validator owns
    mapping(address => bytes32) public operatorRoles; // operator address => role
    mapping(uint128 => uint128) private _validatorActiveOperatorsCounters; // how many operators are enabled per validator given validator id
    mapping(uint64 => mapping(uint64 => BlockSpecimenSession)) private _sessions; // chainId => blockHeight
    mapping(uint64 => ChainData) private _chainData; // by chain id

    EnumerableSetUpgradeable.AddressSet private _blockResultProducers; // currently enabled block result producer operators
    mapping(uint64 => mapping(uint64 => BlockSpecimenSession)) private _blockResultSessions; // chainId => blockHeight
    bytes32 public constant BLOCK_RESULT_PRODUCER_ROLE = keccak256("BLOCK_RESULT_PRODUCER_ROLE");
    uint128 private _brpRequiredStake; // how much a validator should have staked in order to run an operator
    uint128 private _blockResultRewardAllocation; // the reward allocated per block hash

    mapping(bytes32 => string[]) private _urls; // hash => urls

    struct ChainData {
        uint256 blockOnTargetChain; // block number on the chain for which BSP are produced which is mapped to the current chain block
        uint256 blockOnCurrentChain; // block number on the chain where the ProofChain is deployed. it is mapped to the target chain block
        uint256 secondsPerBlock; // average block time on the chain for which BSP is generated
        uint128 allowedThreshold; // block offsett threshold, used to handle minor de-synchronization over time
        uint128 maxSubmissionsPerBlockHeight; // max number of block hashes allowed to submit per block height
        uint64 nthBlock; // block divisor
    }

    struct BlockHash {
        mapping(bytes32 => address[]) participants; // specimen hash => operators who submitted the specimen hash
        bytes32[] specimenHashes; // raw specimen hashes
    }

    struct SessionParticipantData {
        uint128 stake; // stake at the time when an operator submitted the first specimen hash
        uint128 submissionCounter; // how many specimen hashes an operator has submitted
    }

    struct BlockSpecimenSession {
        mapping(bytes32 => BlockHash) blockHashes;
        bytes32[] blockHashesRaw;
        mapping(address => SessionParticipantData) participantsData; // stake and submission counter, pack these together to save gas
        uint64 sessionDeadline; // the last block when an operator can submit a specimen hash
        bool requiresAudit; // auditor can arbitrate the session only if this is set to true
    }

    event OperatorAdded(address operator, uint128 validatorId, bytes32 role);

    event OperatorRemoved(address operator);

    event OperatorEnabled(address operator);

    event OperatorDisabled(address operator);

    event BlockSpecimenProductionProofSubmitted(
        uint64 chainId,
        uint64 blockHeight,
        bytes32 blockHash,
        bytes32 specimenHash, // SHA-256 content-hash of specimen object file;
        string storageURL, // URL of specimen storage
        uint128 submittedStake
    );

    event BSPSessionStarted(uint64 indexed chainId, uint64 indexed blockHeight, uint64 deadline);

    event BRPSessionStarted(uint64 indexed chainId, uint64 indexed blockHeight, uint64 deadline);

    event BlockSpecimenRewardAwarded(uint64 indexed chainId, uint64 indexed blockHeight, bytes32 indexed blockhash, bytes32 specimenhash);

    event BlockResultRewardAwarded(uint64 indexed chainId, uint64 indexed blockHeight, bytes32 indexed specimenHash, bytes32 blockResultHash);

    event BSPQuorumNotReached(uint64 indexed chainId, uint64 blockHeight);

    event BRPQuorumNotReached(uint64 indexed chainId, uint64 blockHeight);

    event BlockSpecimenRewardChanged(uint128 newBlockSpecimenRewardAllocation);

    event MinimumRequiredStakeChanged(uint128 newStakeRequirement);

    event StakingInterfaceChanged(address newInterfaceAddress);

    event SpecimenSessionQuorumChanged(uint256 newQuorumThreshold);

    event SpecimenSessionDurationChanged(uint64 newSessionDuration);

    event SpecimenSessionMinSubmissionChanged(uint64 minSubmissions);

    event NthBlockChanged(uint64 indexed chainId, uint64 indexed nthBlock);

    event MaxSubmissionsPerBlockHeightChanged(uint256 maxSubmissions);

    event ChainSyncDataChanged(uint64 indexed chainId, uint256 blockOnTargetChain, uint256 blockOnCurrentChain, uint256 secondsPerBlock);

    event SecondsPerBlockChanged(uint64 indexed secondsPerBlock);

    event BlockHeightSubmissionThresholdChanged(uint64 indexed chainId, uint64 threshold);

    event MinimumRequiredBlockResultStakeChanged(uint128 newStakeRequirement);

    event BlockResultProductionProofSubmitted(uint64 chainId, uint64 blockHeight, bytes32 specimenHash, bytes32 resultHash, string storageURL, uint128 submittedStake);

    event BlockResultSessionQuorumChanged(uint256 newQuorumThreshold);

    event BlockSpecimenResultChanged(uint128 newBlockResultRewardAllocation);

    event BlockResultRewardChanged(uint128 newBlockSpecimenRewardAllocation);

    modifier onlyGovernor() {
        require(_governors.contains(msg.sender), "Sender is not GOVERNANCE_ROLE");
        _;
    }

    /**
     * Operators will have multiple addresses: the address they submit the proofs from and the address that manages staking and operator instances
     */
    modifier onlyOperatorManager(address operator) {
        (address validatorAddress, , , ) = _stakingInterface.getValidatorMetadata(validatorIDs[operator]);
        require(validatorAddress == msg.sender, "Sender is not operator manager");
        _;
    }

    function initialize(address initialOwner, address stakingContract) public initializer {
        __Ownable_init();

        _governors.add(msg.sender);

        _roleNames.add(GOVERNANCE_ROLE);
        _roleNames.add(BLOCK_SPECIMEN_PRODUCER_ROLE);
        _roleNames.add(AUDITOR_ROLE);

        setQuorumThreshold(_DIVIDER / 2); // 50%
        setBlockSpecimenReward(10 ** 14); // 0.0001
        setSessionDuration(240); // blocks
        setMinSubmissionsRequired(2);
        setStakingInterface(stakingContract);
        _governors.remove(msg.sender);

        operatorRoles[initialOwner] = GOVERNANCE_ROLE;
        _governors.add(initialOwner);
        emit OperatorAdded(initialOwner, 0, GOVERNANCE_ROLE);
    }

    /**
     * Adds operator on the staking contract
     */
    function addValidator(address validator, uint128 commissionRate) external onlyGovernor {
        _stakingInterface.addValidator(validator, commissionRate);
    }

    /**
     * Disables the given operator on the staking contract
     */
    function disableValidator(uint128 validatorId, uint256 blockNumber) external onlyGovernor {
        _stakingInterface.disableValidator(validatorId, blockNumber);
    }

    /**
     * Enables the operator instance. The operators need to call that function before they can start submitting proofs
     */
    function enableBSPOperator(address operator) external onlyOperatorManager(operator) {
        _enableOperator(operator, BLOCK_SPECIMEN_PRODUCER_ROLE, _blockSpecimenProducers);
    }

    /**
     * Enables the operator instance. The operators need to call that function before they can start submitting proofs
     */
    function enableBRPOperator(address operator) external onlyOperatorManager(operator) {
        _enableOperator(operator, BLOCK_RESULT_PRODUCER_ROLE, _blockResultProducers);
    }

    /**
     * Enables the operator instance. The operators need to call that function before they can start submitting proofs
     */
    function _enableOperator(address operator, bytes32 role, EnumerableSetUpgradeable.AddressSet storage operators) internal {
        require(operatorRoles[operator] == role, "Operator does not perform the requested role");
        require(!operators.contains(operator), "Operator is already enabled");
        uint128 validatorId = validatorIDs[operator];
        operators.add(operator);
        _validatorActiveOperatorsCounters[validatorId]++;
        // if no operator was enabled we need to enable the validator instance
        if (_validatorActiveOperatorsCounters[validatorId] == 1) _stakingInterface.enableValidator(validatorId);
        emit OperatorEnabled(operator);
    }

    /**
     * Disables the operator instance. The operator cannot submit proofs its instance got disabled.
     * If all addresses of the operator are disabled, then the operator (validator) instance will get disabled on the staking contract
     */
    function disableBSPOperator(address operator) external onlyOperatorManager(operator) {
        _disableOperator(operator, BLOCK_SPECIMEN_PRODUCER_ROLE, _blockSpecimenProducers);
    }

    /**
     * Disables the operator instance. The operator cannot submit proofs its instance got disabled.
     * If all addresses of the operator are disabled, then the operator (validator) instance will get disabled on the staking contract
     */
    function disableBRPOperator(address operator) external onlyOperatorManager(operator) {
        _disableOperator(operator, BLOCK_RESULT_PRODUCER_ROLE, _blockResultProducers);
    }

    /**
     * Disables the operator instance. The operator cannot submit proofs after its instance got disabled.
     * If all addresses of the operator are disabled, then the operator (validator) instance will get disabled on the staking contract
     */
    function _disableOperator(address operator, bytes32 role, EnumerableSetUpgradeable.AddressSet storage operators) internal {
        require(operatorRoles[operator] == role, "Operator does not perform the requested role");
        require(operators.contains(operator), "Operator is already disabled");
        _removeOperatorFromActiveInstances(operator, operators);
        emit OperatorDisabled(operator);
    }

    /**
     * Adds the given address to the block specimen producers set
     */
    function addBSPOperator(address operator, uint128 validatorId) external onlyGovernor {
        _addOperator(operator, validatorId, BLOCK_SPECIMEN_PRODUCER_ROLE);
    }

    /**
     * Adds the given address to the block result producers set
     */
    function addBRPOperator(address operator, uint128 validatorId) external onlyGovernor {
        _addOperator(operator, validatorId, BLOCK_RESULT_PRODUCER_ROLE);
    }

    /**
     * Adds the given address to the given operator role set
     */
    function _addOperator(address operator, uint128 validatorId, bytes32 role) internal {
        require(operatorRoles[operator] == 0, "Operator already exists");
        operatorRoles[operator] = role;
        validatorIDs[operator] = validatorId;
        _validatorOperators[validatorId].add(operator);
        emit OperatorAdded(operator, validatorId, role);
    }

    /**
     * Removes the given address from the block specimen producers set
     */
    function removeBSPOperator(address operator) external onlyGovernor {
        _removeOperator(operator, BLOCK_SPECIMEN_PRODUCER_ROLE, _blockSpecimenProducers);
    }

    /**
     * Removes the given address from the block specimen producers set
     */
    function removeBRPOperator(address operator) external onlyGovernor {
        _removeOperator(operator, BLOCK_RESULT_PRODUCER_ROLE, _blockResultProducers);
    }

    /**
     * Removes the given address from the operators set
     */
    function _removeOperator(address operator, bytes32 role, EnumerableSetUpgradeable.AddressSet storage operators) internal {
        require(operatorRoles[operator] == role, "Operator does not perform the requested role");
        if (operators.contains(operator)) _removeOperatorFromActiveInstances(operator, operators);
        _validatorOperators[validatorIDs[operator]].remove(operator);
        validatorIDs[operator] = 0;
        operatorRoles[operator] = 0;
        emit OperatorRemoved(operator);
    }

    /**
     * Disables the operator instance.
     * If all addresses of the operator are disabled, then the operator (validator) instance will get disabled on the staking contract
     */
    function _removeOperatorFromActiveInstances(address operator, EnumerableSetUpgradeable.AddressSet storage operators) internal {
        operators.remove(operator);
        uint128 validatorId = validatorIDs[operator];
        _validatorActiveOperatorsCounters[validatorId]--;
        // if there are not more enabled operators left we need to disable the validator instance too
        if (_validatorActiveOperatorsCounters[validatorId] == 0) _stakingInterface.disableValidator(validatorId, block.number);
    }

    /**
     * Adds the given address to the auditors set
     */
    function addAuditor(address auditor) external onlyGovernor {
        require(operatorRoles[auditor] == 0, "Operator already exists");
        operatorRoles[auditor] = AUDITOR_ROLE;
        _auditors.add(auditor);
        emit OperatorAdded(auditor, 0, AUDITOR_ROLE);
    }

    /**
     * Removes the given address from the auditors set
     */
    function removeAuditor(address auditor) external onlyGovernor {
        require(operatorRoles[auditor] == AUDITOR_ROLE, "Operator is not auditor");
        operatorRoles[auditor] = 0;
        _auditors.remove(auditor);
        emit OperatorRemoved(auditor);
    }

    /**
     * Adds the given address to the governors set
     */
    function addGovernor(address governor) external onlyOwner {
        require(operatorRoles[governor] == 0, "Operator already exists");
        operatorRoles[governor] = GOVERNANCE_ROLE;
        _governors.add(governor);
        emit OperatorAdded(governor, 0, GOVERNANCE_ROLE);
    }

    /**
     * Removes the given address from the governors set
     */
    function removeGovernor(address governor) external onlyOwner {
        require(operatorRoles[governor] == GOVERNANCE_ROLE, "Operator is not governor");
        operatorRoles[governor] = 0;
        _governors.remove(governor);
        emit OperatorRemoved(governor);
    }

    /**
     * Updates the amount of tokens required to stake in order to be able to submit the proofs
     */
    function setBSPRequiredStake(uint128 newStakeAmount) public onlyGovernor {
        _bspRequiredStake = newStakeAmount;
        emit MinimumRequiredStakeChanged(newStakeAmount);
    }

    /**
     * Updates the amount of tokens required to stake in order to be able to submit the proofs
     */
    function setBRPRequiredStake(uint128 newStakeAmount) public onlyGovernor {
        _brpRequiredStake = newStakeAmount;
        emit MinimumRequiredBlockResultStakeChanged(newStakeAmount);
    }

    /**
     * Updates the address of the staking contract
     */
    function setStakingInterface(address stakingContractAddress) public onlyGovernor {
        _stakingInterface = IOperationalStaking(stakingContractAddress);
        emit StakingInterfaceChanged(stakingContractAddress);
    }

    /**
     * Update the Block Specimen Quorum Threshold.
     */
    function setQuorumThreshold(uint256 quorum) public onlyGovernor {
        _blockSpecimenQuorum = quorum;
        emit SpecimenSessionQuorumChanged(quorum);
    }

    /**
     * Update block divisor
     */
    function setNthBlock(uint64 chainId, uint64 n) public onlyGovernor {
        _chainData[chainId].nthBlock = n;
        emit NthBlockChanged(chainId, n);
    }

    /**
     * Update the reward allocation per block specimen.
     */
    function setBlockSpecimenReward(uint128 newBlockSpecimenReward) public onlyGovernor {
        _blockSpecimenRewardAllocation = newBlockSpecimenReward;
        emit BlockSpecimenRewardChanged(newBlockSpecimenReward);
    }

    /**
     * Update the reward allocation per block specimen.
     */
    function setBlockResultReward(uint128 newBlockResultReward) public onlyGovernor {
        _blockResultRewardAllocation = newBlockResultReward;
        emit BlockResultRewardChanged(newBlockResultReward);
    }

    /**
     * Update the duration of a specimen session in blocks
     */
    function setSessionDuration(uint64 newSessionDuration) public onlyGovernor {
        _blockSpecimenSessionDuration = newSessionDuration;
        emit SpecimenSessionDurationChanged(newSessionDuration);
    }

    /**
     * Update the minimum # of submissions required in order to reach quorum
     */
    function setMinSubmissionsRequired(uint64 minSubmissions) public onlyGovernor {
        _minSubmissionsRequired = minSubmissions;
        emit SpecimenSessionMinSubmissionChanged(minSubmissions);
    }

    /**
     * Update the max # of submissions per operator per block height
     */
    function setMaxSubmissionsPerBlockHeight(uint64 chainId, uint64 maxSubmissions) public onlyGovernor {
        _chainData[chainId].maxSubmissionsPerBlockHeight = maxSubmissions;
        emit MaxSubmissionsPerBlockHeightChanged(maxSubmissions);
    }

    /**
     * Update chain sync data
     */
    function setChainSyncData(uint64 chainId, uint256 blockOnTargetChain, uint256 blockOnCurrentChain, uint256 secondsPerBlock) external onlyGovernor {
        ChainData storage cd = _chainData[chainId];
        require(secondsPerBlock > 0, "Seconds per block cannot be 0");
        cd.blockOnTargetChain = blockOnTargetChain;
        cd.blockOnCurrentChain = blockOnCurrentChain;
        cd.secondsPerBlock = secondsPerBlock;
        emit ChainSyncDataChanged(chainId, blockOnTargetChain, blockOnCurrentChain, secondsPerBlock);
    }

    /**
     * Update block height submission threshold for live sync
     */
    function setBlockHeightSubmissionsThreshold(uint64 chainId, uint64 threshold) external onlyGovernor {
        _chainData[chainId].allowedThreshold = threshold;
        emit BlockHeightSubmissionThresholdChanged(chainId, threshold);
    }

    /**
     * Update seconds per block on the chain where the ProofChain is deployed
     */
    function setSecondsPerBlock(uint64 secondsPerBlock) external onlyGovernor {
        _secondsPerBlock = secondsPerBlock;
        emit SecondsPerBlockChanged(secondsPerBlock);
    }

    function submitBlockSpecimenProof(uint64 chainId, uint64 blockHeight, bytes32 blockHash, bytes32 specimenHash, string calldata storageURL) external {
        _submitProof(chainId, blockHeight, blockHash, specimenHash, storageURL, true);
    }

    function submitBlockResultProof(uint64 chainId, uint64 blockHeight, bytes32 blockHash, bytes32 specimenHash, string calldata storageURL) external {
        _submitProof(chainId, blockHeight, blockHash, specimenHash, storageURL, false);
    }

    /**
     * That function exists because submitProof has too many local variables
     */
    function _startSession(
        uint64 chainId,
        uint64 blockHeight,
        bytes32 blockHash,
        bytes32 specimenHash,
        ChainData storage cd,
        BlockSpecimenSession storage session,
        bool bspSession,
        SessionParticipantData storage participantsData
    ) internal {
        require(!session.requiresAudit, "Session submissions have closed");
        uint256 currentBlockOnTargetChain = cd.blockOnTargetChain + (((block.number - cd.blockOnCurrentChain) * _secondsPerBlock) / cd.secondsPerBlock);
        uint256 lowerBound = currentBlockOnTargetChain >= cd.allowedThreshold ? currentBlockOnTargetChain - cd.allowedThreshold : 0;
        require(lowerBound <= blockHeight && blockHeight <= currentBlockOnTargetChain + cd.allowedThreshold, "Block height is out of bounds for live sync");
        session.sessionDeadline = uint64(block.number + _blockSpecimenSessionDuration);
        (uint128 baseStake, uint128 delegateStakes) = _stakingInterface.getValidatorCompoundedStakingData(validatorIDs[msg.sender]);
        require(baseStake >= (bspSession ? _bspRequiredStake : _brpRequiredStake), "Insufficiently staked to submit");
        participantsData.stake = baseStake + delegateStakes;
        session.blockHashesRaw.push(blockHash);
        BlockHash storage bh = session.blockHashes[blockHash];
        bh.specimenHashes.push(specimenHash);
        bh.participants[specimenHash].push(msg.sender);
        participantsData.submissionCounter++;
        // no need to have a separate session started event for BRP or BSP since there is another submit proof event emitted
        if (bspSession) emit BSPSessionStarted(chainId, blockHeight, session.sessionDeadline);
        else emit BRPSessionStarted(chainId, blockHeight, session.sessionDeadline);
    }

    /**
     * Block Specimen Producers submit their block specimen proofs using this function.
     */
    function _submitProof(uint64 chainId, uint64 blockHeight, bytes32 blockHash, bytes32 specimenHash, string calldata storageURL, bool bspSession) internal {
        if (bspSession) require(_blockSpecimenProducers.contains(msg.sender), "Sender is not BLOCK_SPECIMEN_PRODUCER_ROLE");
        else require(_blockResultProducers.contains(msg.sender), "Sender is not BLOCK_RESULT_PRODUCER_ROLE");

        ChainData storage cd = _chainData[chainId];
        require(cd.nthBlock != 0, "Invalid chain ID");
        require(blockHeight % cd.nthBlock == 0, "Invalid block height");

        BlockSpecimenSession storage session = bspSession ? _sessions[chainId][blockHeight] : _blockResultSessions[chainId][blockHeight];
        uint64 sessionDeadline = session.sessionDeadline;
        SessionParticipantData storage participantsData = session.participantsData[msg.sender];
        // if this is the first specimen to be submitted for a block, initialize a new session
        if (sessionDeadline == 0) {
            _startSession(chainId, blockHeight, blockHash, specimenHash, cd, session, bspSession, participantsData);
        } else {
            require(block.number <= sessionDeadline, "Session submissions have closed");
            require(participantsData.submissionCounter < cd.maxSubmissionsPerBlockHeight, "Max submissions limit exceeded");

            BlockHash storage bh = session.blockHashes[blockHash];
            bytes32[] storage specimenHashes = bh.specimenHashes;
            if (participantsData.stake != 0) {
                // check if it was submitted for the same block hash
                // this should be at most 10 iterations
                for (uint256 j = 0; j < specimenHashes.length; j++) {
                    address[] storage specimenHashParticipants = bh.participants[specimenHashes[j]];
                    for (uint256 k = 0; k < specimenHashParticipants.length; k++)
                        require(specimenHashParticipants[k] != msg.sender, "Operator already submitted for the provided block hash");
                }
            } else {
                (uint128 baseStake, uint128 delegateStakes) = _stakingInterface.getValidatorCompoundedStakingData(validatorIDs[msg.sender]);
                require(baseStake >= (bspSession ? _bspRequiredStake : _brpRequiredStake), "Insufficiently staked to submit");
                participantsData.stake = baseStake + delegateStakes;
            }

            address[] storage participants = bh.participants[specimenHash];
            if (specimenHashes.length != 0) {
                if (participants.length == 0) specimenHashes.push(specimenHash);
            } else {
                session.blockHashesRaw.push(blockHash);
                specimenHashes.push(specimenHash);
            }

            participants.push(msg.sender);
            participantsData.submissionCounter++;
        }
        _urls[specimenHash].push(storageURL);
        if (bspSession) emit BlockSpecimenProductionProofSubmitted(chainId, blockHeight, blockHash, specimenHash, storageURL, participantsData.stake);
        else emit BlockResultProductionProofSubmitted(chainId, blockHeight, blockHash, specimenHash, storageURL, participantsData.stake);
    }

    /**
     * This function is called to check whether the sesion is open for the given chain id and block height
     */
    function isSessionOpen(uint64 chainId, uint64 blockHeight, bool bspSession, address operator) public view returns (bool) {
        BlockSpecimenSession storage session = bspSession ? _sessions[chainId][blockHeight] : _blockResultSessions[chainId][blockHeight];
        uint64 sessionDeadline = session.sessionDeadline;
        SessionParticipantData storage participantsData = session.participantsData[operator];
        // assuming for brp sessions it can only submit once since only one block specimen is finalized right now
        bool submissionLimitExceeded = bspSession
            ? participantsData.submissionCounter == _chainData[chainId].maxSubmissionsPerBlockHeight
            : participantsData.submissionCounter == 1;
        return (!submissionLimitExceeded && block.number <= sessionDeadline) || (sessionDeadline == 0 && !session.requiresAudit);
    }

    /**
     * This function is called when a quorum of equivalent hashes have been submitted for a Block Specimen Session.
     */
    function finalizeAndRewardSpecimenSession(uint64 chainId, uint64 blockHeight) public {
        _finalizeAndRewardSession(chainId, blockHeight, true);
    }

    /**
     * This function is called when a quorum of equivalent hashes have been submitted for a Block Specimen Session.
     */
    function finalizeAndRewardBlockResultSession(uint64 chainId, uint64 blockHeight) public {
        _finalizeAndRewardSession(chainId, blockHeight, false);
    }

    /**
     * This function is called when a quorum of equivalent hashes have been submitted for a Block Specimen Session.
     */
    function _finalizeAndRewardSession(uint64 chainId, uint64 blockHeight, bool bspSession) internal {
        BlockSpecimenSession storage session = bspSession ? _sessions[chainId][blockHeight] : _blockResultSessions[chainId][blockHeight];
        uint64 sessionDeadline = session.sessionDeadline;
        require(block.number > sessionDeadline, "Session not past deadline");
        require(!session.requiresAudit, "Session cannot be finalized");
        require(sessionDeadline != 0, "Session not started");

        uint256 contributorsN;
        bytes32 specimenHash;

        uint256 max;
        bytes32 agreedBlockHash;
        bytes32 agreedSpecimenHash;

        bytes32[] storage blockHashesRaw = session.blockHashesRaw;
        bytes32 rawBlockHash;

        // find the block hash and specimen hashes that the quorum agrees on by finding the specimen hash with the highest number of participants
        for (uint256 i = 0; i < blockHashesRaw.length; i++) {
            rawBlockHash = blockHashesRaw[i];
            BlockHash storage bh = session.blockHashes[rawBlockHash];
            for (uint256 j = 0; j < bh.specimenHashes.length; j++) {
                specimenHash = bh.specimenHashes[j];
                uint256 len = bh.participants[specimenHash].length;
                contributorsN += len;
                if (len > max) {
                    max = len;
                    agreedBlockHash = rawBlockHash;
                    agreedSpecimenHash = specimenHash;
                }
            }
        }
        // check if the number of submissions is sufficient and if the quorum is achieved
        if (_minSubmissionsRequired <= max && (max * _DIVIDER) / contributorsN > _blockSpecimenQuorum)
            _rewardParticipants(session, chainId, blockHeight, agreedBlockHash, agreedSpecimenHash, bspSession);
        else {
            if (bspSession) emit BSPQuorumNotReached(chainId, blockHeight);
            else emit BRPQuorumNotReached(chainId, blockHeight);
        }

        session.requiresAudit = true;
        // set session deadline to 0 to release gas
        session.sessionDeadline = 0;
    }

    /**
     * Called by Auditor role when a quorum is not reached. The auditor's submitted hash is
     * the definitive truth.
     */
    function arbitrateBlockSpecimenSession(uint64 chainId, uint64 blockHeight, bytes32 blockHash, bytes32 definitiveSpecimenHash) public {
        _arbitrateSession(chainId, blockHeight, blockHash, definitiveSpecimenHash, true);
    }

    /**
     * Called by Auditor role when a quorum is not reached. The auditor's submitted hash is
     * the definitive truth.
     */
    function arbitrateBlockResultSession(uint64 chainId, uint64 blockHeight, bytes32 blockHash, bytes32 definitiveSpecimenHash) public {
        _arbitrateSession(chainId, blockHeight, blockHash, definitiveSpecimenHash, false);
    }

    /**
     * Called by Auditor role when a quorum is not reached. The auditor's submitted hash is
     * the definitive truth.
     */
    function _arbitrateSession(uint64 chainId, uint64 blockHeight, bytes32 blockHash, bytes32 definitiveSpecimenHash, bool bspSession) internal {
        require(_auditors.contains(msg.sender), "Sender is not AUDITOR_ROLE");
        BlockSpecimenSession storage session = bspSession ? _sessions[chainId][blockHeight] : _blockResultSessions[chainId][blockHeight];
        require(session.requiresAudit, "Session must be finalized before audit");
        _rewardParticipants(session, chainId, blockHeight, blockHash, definitiveSpecimenHash, bspSession);
    }

    function _rewardParticipants(BlockSpecimenSession storage session, uint64 chainId, uint64 blockHeight, bytes32 blockHash, bytes32 specimenHash, bool bspSession) internal {
        address participant;
        address[] storage participants = session.blockHashes[blockHash].participants[specimenHash];
        uint256 len = participants.length;
        uint128[] memory ids = new uint128[](len);
        uint128[] memory rewards = new uint128[](len);
        uint128 totalStake;
        mapping(address => SessionParticipantData) storage participantsData = session.participantsData;
        for (uint256 i = 0; i < len; i++) {
            totalStake += participantsData[participants[i]].stake;
        }
        for (uint256 i = 0; i < len; i++) {
            participant = participants[i];
            SessionParticipantData storage pd = participantsData[participant];
            ids[i] = validatorIDs[participant];
            rewards[i] = uint128((uint256(pd.stake) * uint256(_blockSpecimenRewardAllocation)) / totalStake);
            // release gas if possible
            if (pd.submissionCounter == 1) {
                pd.submissionCounter = 0;
                pd.stake = 0;
            }
        }
        _stakingInterface.rewardValidators(ids, rewards);
        if (bspSession) emit BlockSpecimenRewardAwarded(chainId, blockHeight, blockHash, specimenHash);
        else emit BlockResultRewardAwarded(chainId, blockHeight, blockHash, specimenHash);

        delete session.blockHashes[blockHash]; // release gas
    }

    /**
     * Returns contract meta data
     */
    function getMetadata()
        public
        view
        returns (
            address stakingInterface,
            uint128 blockSpecimenRewardAllocation,
            uint128 blockResultRewardAllocation,
            uint64 blockSpecimenSessionDuration,
            uint64 minSubmissionsRequired,
            uint256 blockSpecimenQuorum,
            uint256 secondsPerBlock
        )
    {
        return (
            address(_stakingInterface),
            _blockSpecimenRewardAllocation,
            _blockResultRewardAllocation,
            _blockSpecimenSessionDuration,
            _minSubmissionsRequired,
            _blockSpecimenQuorum,
            _secondsPerBlock
        );
    }

    /**
     * Returns data used for chain sync
     */
    function getChainData(
        uint64 chainId
    )
        external
        view
        returns (uint256 blockOnTargetChain, uint256 blockOnCurrentChain, uint256 secondsPerBlock, uint128 allowedThreshold, uint128 maxSubmissionsPerBlockHeight, uint64 nthBlock)
    {
        ChainData memory cd = _chainData[chainId];
        return (cd.blockOnTargetChain, cd.blockOnCurrentChain, cd.secondsPerBlock, cd.allowedThreshold, cd.maxSubmissionsPerBlockHeight, cd.nthBlock);
    }

    /**
     * Returns all operator addresses (disabled and enabled) of a given validator
     */
    function getOperators(uint128 validatorId) external view returns (address[] memory) {
        return _validatorOperators[validatorId].values();
    }

    /**
     * Returns all enabled operators by role type
     */
    function getAllOperators() external view returns (address[] memory _bsps, address[] memory __governors, address[] memory __auditors, address[] memory _brps) {
        return (_blockSpecimenProducers.values(), _governors.values(), _auditors.values(), _blockResultProducers.values());
    }

    /**
     * Returns required stake and enabled block specimen producer operators
     */
    function getBSPRoleData() external view returns (uint128 requiredStake, address[] memory activeMembers) {
        return (_bspRequiredStake, _blockSpecimenProducers.values());
    }

    /**
     * Returns required stake and enabled block result producer operators
     */
    function getBRPRoleData() external view returns (uint128 requiredStake, address[] memory activeMembers) {
        return (_brpRequiredStake, _blockResultProducers.values());
    }

    function getURLS(bytes32 specimenhash) external view returns (string[] memory) {
        return _urls[specimenhash];
    }

    /**
     * Returns true if the given operator is enabled.
     * Returns false if the operator is disabled or does not exist
     */
    function isEnabled(address operator) external view returns (bool) {
        return _blockSpecimenProducers.contains(operator) || _blockResultProducers.contains(operator);
    }
}

File 2 of 7 : IOperationalStaking.sol
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.13;

interface IOperationalStaking {
    function getValidatorMetadata(uint128 validatorId)
        external
        view
        returns (
            address _address,
            uint128 staked,
            uint128 delegated,
            uint128 commissionRate
        );

    function getValidatorStakingData(uint128 validatorId) external view returns (uint128 staked, uint128 delegated);

    function getValidatorCompoundedStakingData(uint128 validatorId) external view returns (uint128 staked, uint128 delegated);

    function rewardValidators(uint128[] calldata validatorId, uint128[] calldata amount) external;

    function addValidator(address validator, uint128 commissionRate) external returns (uint256 id);

    function disableValidator(uint128 validatorId, uint256 blockNumber) external;

    function enableValidator(uint128 validatorId) external;
}

File 3 of 7 : EnumerableSetUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/structs/EnumerableSet.sol)

pragma solidity ^0.8.0;

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
 * and `uint256` (`UintSet`) are supported.
 *
 * [WARNING]
 * ====
 *  Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable.
 *  See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
 *
 *  In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet.
 * ====
 */
library EnumerableSetUpgradeable {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        bytes32[] _values;
        // Position of the value in the `values` array, plus 1 because index 0
        // means a value is not in the set.
        mapping(bytes32 => uint256) _indexes;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function _add(Set storage set, bytes32 value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._indexes[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function _remove(Set storage set, bytes32 value) private returns (bool) {
        // We read and store the value's index to prevent multiple reads from the same storage slot
        uint256 valueIndex = set._indexes[value];

        if (valueIndex != 0) {
            // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 toDeleteIndex = valueIndex - 1;
            uint256 lastIndex = set._values.length - 1;

            if (lastIndex != toDeleteIndex) {
                bytes32 lastValue = set._values[lastIndex];

                // Move the last value to the index where the value to delete is
                set._values[toDeleteIndex] = lastValue;
                // Update the index for the moved value
                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
            }

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the index for the deleted slot
            delete set._indexes[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function _contains(Set storage set, bytes32 value) private view returns (bool) {
        return set._indexes[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function _at(Set storage set, uint256 index) private view returns (bytes32) {
        return set._values[index];
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function _values(Set storage set) private view returns (bytes32[] memory) {
        return set._values;
    }

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _add(set._inner, value);
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _remove(set._inner, value);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
        return _contains(set._inner, value);
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
        return _values(set._inner);
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address value) internal returns (bool) {
        return _add(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address value) internal returns (bool) {
        return _remove(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address value) internal view returns (bool) {
        return _contains(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(AddressSet storage set, uint256 index) internal view returns (address) {
        return address(uint160(uint256(_at(set._inner, index))));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(AddressSet storage set) internal view returns (address[] memory) {
        bytes32[] memory store = _values(set._inner);
        address[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // UintSet

    struct UintSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(UintSet storage set, uint256 value) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(UintSet storage set, uint256 value) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(UintSet storage set, uint256 index) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(UintSet storage set) internal view returns (uint256[] memory) {
        bytes32[] memory store = _values(set._inner);
        uint256[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }
}

File 4 of 7 : OwnableUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    function __Ownable_init() internal onlyInitializing {
        __Ownable_init_unchained();
    }

    function __Ownable_init_unchained() internal onlyInitializing {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[49] private __gap;
}

File 5 of 7 : ContextUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract ContextUpgradeable is Initializable {
    function __Context_init() internal onlyInitializing {
    }

    function __Context_init_unchained() internal onlyInitializing {
    }
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}

File 6 of 7 : Initializable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.2;

import "../../utils/AddressUpgradeable.sol";

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
 * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
 * case an upgrade adds a module that needs to be initialized.
 *
 * For example:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * contract MyToken is ERC20Upgradeable {
 *     function initialize() initializer public {
 *         __ERC20_init("MyToken", "MTK");
 *     }
 * }
 * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
 *     function initializeV2() reinitializer(2) public {
 *         __ERC20Permit_init("MyToken");
 *     }
 * }
 * ```
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
 * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() {
 *     _disableInitializers();
 * }
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Indicates that the contract has been initialized.
     * @custom:oz-retyped-from bool
     */
    uint8 private _initialized;

    /**
     * @dev Indicates that the contract is in the process of being initialized.
     */
    bool private _initializing;

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint8 version);

    /**
     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
     * `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`.
     */
    modifier initializer() {
        bool isTopLevelCall = !_initializing;
        require(
            (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
            "Initializable: contract is already initialized"
        );
        _initialized = 1;
        if (isTopLevelCall) {
            _initializing = true;
        }
        _;
        if (isTopLevelCall) {
            _initializing = false;
            emit Initialized(1);
        }
    }

    /**
     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
     * used to initialize parent contracts.
     *
     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original
     * initialization step. This is essential to configure modules that are added through upgrades and that require
     * initialization.
     *
     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
     * a contract, executing them in the right order is up to the developer or operator.
     */
    modifier reinitializer(uint8 version) {
        require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
        _initialized = version;
        _initializing = true;
        _;
        _initializing = false;
        emit Initialized(version);
    }

    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} and {reinitializer} modifiers, directly or indirectly.
     */
    modifier onlyInitializing() {
        require(_initializing, "Initializable: contract is not initializing");
        _;
    }

    /**
     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
     * through proxies.
     */
    function _disableInitializers() internal virtual {
        require(!_initializing, "Initializable: contract is initializing");
        if (_initialized < type(uint8).max) {
            _initialized = type(uint8).max;
            emit Initialized(type(uint8).max);
        }
    }
}

File 7 of 7 : AddressUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library AddressUpgradeable {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCall(target, data, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly
                /// @solidity memory-safe-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 1000000
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract ABI

[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"chainId","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"blockHeight","type":"uint64"}],"name":"BRPQuorumNotReached","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"chainId","type":"uint64"},{"indexed":true,"internalType":"uint64","name":"blockHeight","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"deadline","type":"uint64"}],"name":"BRPSessionStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"chainId","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"blockHeight","type":"uint64"}],"name":"BSPQuorumNotReached","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"chainId","type":"uint64"},{"indexed":true,"internalType":"uint64","name":"blockHeight","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"deadline","type":"uint64"}],"name":"BSPSessionStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"chainId","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"threshold","type":"uint64"}],"name":"BlockHeightSubmissionThresholdChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"chainId","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"blockHeight","type":"uint64"},{"indexed":false,"internalType":"bytes32","name":"specimenHash","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"resultHash","type":"bytes32"},{"indexed":false,"internalType":"string","name":"storageURL","type":"string"},{"indexed":false,"internalType":"uint128","name":"submittedStake","type":"uint128"}],"name":"BlockResultProductionProofSubmitted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"chainId","type":"uint64"},{"indexed":true,"internalType":"uint64","name":"blockHeight","type":"uint64"},{"indexed":true,"internalType":"bytes32","name":"specimenHash","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"blockResultHash","type":"bytes32"}],"name":"BlockResultRewardAwarded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint128","name":"newBlockSpecimenRewardAllocation","type":"uint128"}],"name":"BlockResultRewardChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newQuorumThreshold","type":"uint256"}],"name":"BlockResultSessionQuorumChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"chainId","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"blockHeight","type":"uint64"},{"indexed":false,"internalType":"bytes32","name":"blockHash","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"specimenHash","type":"bytes32"},{"indexed":false,"internalType":"string","name":"storageURL","type":"string"},{"indexed":false,"internalType":"uint128","name":"submittedStake","type":"uint128"}],"name":"BlockSpecimenProductionProofSubmitted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint128","name":"newBlockResultRewardAllocation","type":"uint128"}],"name":"BlockSpecimenResultChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"chainId","type":"uint64"},{"indexed":true,"internalType":"uint64","name":"blockHeight","type":"uint64"},{"indexed":true,"internalType":"bytes32","name":"blockhash","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"specimenhash","type":"bytes32"}],"name":"BlockSpecimenRewardAwarded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint128","name":"newBlockSpecimenRewardAllocation","type":"uint128"}],"name":"BlockSpecimenRewardChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"chainId","type":"uint64"},{"indexed":false,"internalType":"uint256","name":"blockOnTargetChain","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"blockOnCurrentChain","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"secondsPerBlock","type":"uint256"}],"name":"ChainSyncDataChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxSubmissions","type":"uint256"}],"name":"MaxSubmissionsPerBlockHeightChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint128","name":"newStakeRequirement","type":"uint128"}],"name":"MinimumRequiredBlockResultStakeChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint128","name":"newStakeRequirement","type":"uint128"}],"name":"MinimumRequiredStakeChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"chainId","type":"uint64"},{"indexed":true,"internalType":"uint64","name":"nthBlock","type":"uint64"}],"name":"NthBlockChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"uint128","name":"validatorId","type":"uint128"},{"indexed":false,"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"OperatorAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"operator","type":"address"}],"name":"OperatorDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"operator","type":"address"}],"name":"OperatorEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"operator","type":"address"}],"name":"OperatorRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"secondsPerBlock","type":"uint64"}],"name":"SecondsPerBlockChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"newSessionDuration","type":"uint64"}],"name":"SpecimenSessionDurationChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"minSubmissions","type":"uint64"}],"name":"SpecimenSessionMinSubmissionChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newQuorumThreshold","type":"uint256"}],"name":"SpecimenSessionQuorumChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newInterfaceAddress","type":"address"}],"name":"StakingInterfaceChanged","type":"event"},{"inputs":[],"name":"AUDITOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BLOCK_RESULT_PRODUCER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BLOCK_SPECIMEN_PRODUCER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GOVERNANCE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"auditor","type":"address"}],"name":"addAuditor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint128","name":"validatorId","type":"uint128"}],"name":"addBRPOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint128","name":"validatorId","type":"uint128"}],"name":"addBSPOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"governor","type":"address"}],"name":"addGovernor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"validator","type":"address"},{"internalType":"uint128","name":"commissionRate","type":"uint128"}],"name":"addValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"chainId","type":"uint64"},{"internalType":"uint64","name":"blockHeight","type":"uint64"},{"internalType":"bytes32","name":"blockHash","type":"bytes32"},{"internalType":"bytes32","name":"definitiveSpecimenHash","type":"bytes32"}],"name":"arbitrateBlockResultSession","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"chainId","type":"uint64"},{"internalType":"uint64","name":"blockHeight","type":"uint64"},{"internalType":"bytes32","name":"blockHash","type":"bytes32"},{"internalType":"bytes32","name":"definitiveSpecimenHash","type":"bytes32"}],"name":"arbitrateBlockSpecimenSession","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"disableBRPOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"disableBSPOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"validatorId","type":"uint128"},{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"disableValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"enableBRPOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"enableBSPOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"chainId","type":"uint64"},{"internalType":"uint64","name":"blockHeight","type":"uint64"}],"name":"finalizeAndRewardBlockResultSession","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"chainId","type":"uint64"},{"internalType":"uint64","name":"blockHeight","type":"uint64"}],"name":"finalizeAndRewardSpecimenSession","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getAllOperators","outputs":[{"internalType":"address[]","name":"_bsps","type":"address[]"},{"internalType":"address[]","name":"__governors","type":"address[]"},{"internalType":"address[]","name":"__auditors","type":"address[]"},{"internalType":"address[]","name":"_brps","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBRPRoleData","outputs":[{"internalType":"uint128","name":"requiredStake","type":"uint128"},{"internalType":"address[]","name":"activeMembers","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBSPRoleData","outputs":[{"internalType":"uint128","name":"requiredStake","type":"uint128"},{"internalType":"address[]","name":"activeMembers","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"chainId","type":"uint64"}],"name":"getChainData","outputs":[{"internalType":"uint256","name":"blockOnTargetChain","type":"uint256"},{"internalType":"uint256","name":"blockOnCurrentChain","type":"uint256"},{"internalType":"uint256","name":"secondsPerBlock","type":"uint256"},{"internalType":"uint128","name":"allowedThreshold","type":"uint128"},{"internalType":"uint128","name":"maxSubmissionsPerBlockHeight","type":"uint128"},{"internalType":"uint64","name":"nthBlock","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMetadata","outputs":[{"internalType":"address","name":"stakingInterface","type":"address"},{"internalType":"uint128","name":"blockSpecimenRewardAllocation","type":"uint128"},{"internalType":"uint128","name":"blockResultRewardAllocation","type":"uint128"},{"internalType":"uint64","name":"blockSpecimenSessionDuration","type":"uint64"},{"internalType":"uint64","name":"minSubmissionsRequired","type":"uint64"},{"internalType":"uint256","name":"blockSpecimenQuorum","type":"uint256"},{"internalType":"uint256","name":"secondsPerBlock","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint128","name":"validatorId","type":"uint128"}],"name":"getOperators","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"specimenhash","type":"bytes32"}],"name":"getURLS","outputs":[{"internalType":"string[]","name":"","type":"string[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"initialOwner","type":"address"},{"internalType":"address","name":"stakingContract","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"isEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"chainId","type":"uint64"},{"internalType":"uint64","name":"blockHeight","type":"uint64"},{"internalType":"bool","name":"bspSession","type":"bool"},{"internalType":"address","name":"operator","type":"address"}],"name":"isSessionOpen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"operatorRoles","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"auditor","type":"address"}],"name":"removeAuditor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"removeBRPOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"removeBSPOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"governor","type":"address"}],"name":"removeGovernor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"newStakeAmount","type":"uint128"}],"name":"setBRPRequiredStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"newStakeAmount","type":"uint128"}],"name":"setBSPRequiredStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"chainId","type":"uint64"},{"internalType":"uint64","name":"threshold","type":"uint64"}],"name":"setBlockHeightSubmissionsThreshold","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"newBlockResultReward","type":"uint128"}],"name":"setBlockResultReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"newBlockSpecimenReward","type":"uint128"}],"name":"setBlockSpecimenReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"chainId","type":"uint64"},{"internalType":"uint256","name":"blockOnTargetChain","type":"uint256"},{"internalType":"uint256","name":"blockOnCurrentChain","type":"uint256"},{"internalType":"uint256","name":"secondsPerBlock","type":"uint256"}],"name":"setChainSyncData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"chainId","type":"uint64"},{"internalType":"uint64","name":"maxSubmissions","type":"uint64"}],"name":"setMaxSubmissionsPerBlockHeight","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"minSubmissions","type":"uint64"}],"name":"setMinSubmissionsRequired","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"chainId","type":"uint64"},{"internalType":"uint64","name":"n","type":"uint64"}],"name":"setNthBlock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"quorum","type":"uint256"}],"name":"setQuorumThreshold","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"secondsPerBlock","type":"uint64"}],"name":"setSecondsPerBlock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"newSessionDuration","type":"uint64"}],"name":"setSessionDuration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"stakingContractAddress","type":"address"}],"name":"setStakingInterface","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"chainId","type":"uint64"},{"internalType":"uint64","name":"blockHeight","type":"uint64"},{"internalType":"bytes32","name":"blockHash","type":"bytes32"},{"internalType":"bytes32","name":"specimenHash","type":"bytes32"},{"internalType":"string","name":"storageURL","type":"string"}],"name":"submitBlockResultProof","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"chainId","type":"uint64"},{"internalType":"uint64","name":"blockHeight","type":"uint64"},{"internalType":"bytes32","name":"blockHash","type":"bytes32"},{"internalType":"bytes32","name":"specimenHash","type":"bytes32"},{"internalType":"string","name":"storageURL","type":"string"}],"name":"submitBlockSpecimenProof","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"validatorIDs","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"}]

608060405234801561001057600080fd5b50615ca880620000216000396000f3fe608060405234801561001057600080fd5b506004361061034c5760003560e01c806389587f05116101bd578063cc96e413116100f9578063df4112c2116100a2578063e6116cfd1161007c578063e6116cfd14610917578063eecdac881461092a578063f2fde38b1461093d578063f36c8f5c1461095057600080fd5b8063df4112c2146108de578063e3201409146108f1578063e429cef11461090457600080fd5b8063d5839da9116100d3578063d5839da914610893578063d911c632146108b3578063dd36a8d5146108cb57600080fd5b8063cc96e4131461084d578063cf64a01d14610860578063d3a8b2a81461087357600080fd5b80639914628411610166578063ad9e91ee11610140578063ad9e91ee14610801578063c0e745d214610814578063c384678914610827578063c4499cb91461083a57600080fd5b806399146284146107b45780639c49d8ee146107c7578063a2e7e441146107ee57600080fd5b80639015d371116101975780639015d37114610776578063920036b71461079957806393742b56146107a157600080fd5b806389587f05146107285780638da5cb5b1461073b5780638ecd30bc1461076357600080fd5b8063485cc9551161028c57806367585e44116102355780636e1d616e1161020f5780636e1d616e14610648578063715018a61461066f57806372ab8568146106775780637a5b4f591461068a57600080fd5b806367585e44146106025780636ab9d8e8146106155780636b7511cb1461063557600080fd5b80635a5e84f2116102665780635a5e84f2146105c95780635ebdedfa146105dc5780636543413a146105ef57600080fd5b8063485cc955146104b45780635137b8b9146104c757806354cfa69f146104da57600080fd5b80632f01798e116102f957806341c1278d116102d357806341c1278d1461044657806341ca4a551461047b5780634414beeb1461048e5780634524c7e1146104a157600080fd5b80632f01798e1461040d5780633646aded146104205780633c4a25d01461043357600080fd5b80631fd55ae91161032a5780631fd55ae9146103d1578063222388c2146103e75780632c58ed42146103fa57600080fd5b80630d92f4ed1461035157806313e3f452146103a9578063151fd8f3146103be575b600080fd5b61038361035f366004615356565b6072602052600090815260409020546fffffffffffffffffffffffffffffffff1681565b6040516fffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6103bc6103b7366004615356565b610977565b005b6103bc6103cc366004615390565b610aed565b6103d9610b05565b6040516103a0929190615487565b6103bc6103f53660046154d8565b610b46565b6103bc610408366004615511565b610beb565b6103bc61041b366004615544565b610ce4565b6103bc61042e366004615356565b610dc8565b6103bc610441366004615356565b610eb1565b61046d7f77ae3b5d012484be69eeed881350adb3189b651fac6e88b31ddff30c833a8b7f81565b6040519081526020016103a0565b6103bc610489366004615356565b611010565b6103bc61049c36600461555f565b61117c565b6103bc6104af3660046155a1565b611190565b6103bc6104c23660046155ba565b61123a565b6103bc6104d53660046155e8565b611575565b61057d6104e8366004615544565b67ffffffffffffffff908116600090815260776020908152604091829020825160c08101845281548082526001830154938201849052600283015494820185905260038301546fffffffffffffffffffffffffffffffff80821660608501819052700100000000000000000000000000000000909204166080840181905260049094015490961660a090920182905295929492565b604080519687526020870195909552938501929092526fffffffffffffffffffffffffffffffff908116606085015216608083015267ffffffffffffffff1660a082015260c0016103a0565b6103bc6105d73660046155e8565b61164f565b6103bc6105ea366004615511565b611729565b6103bc6105fd366004615390565b611735565b6103bc610610366004615511565b611745565b61046d610623366004615356565b60746020526000908152604090205481565b6103bc610643366004615356565b611841565b61046d7f59a1c48e5837ad7a7f3dcedcbe129bf3249ec4fbf651fd4f5e2600ead39fe2f581565b6103bc6118e6565b6103bc610685366004615356565b6118fa565b606554606854607b546069546066546067546040805173ffffffffffffffffffffffffffffffffffffffff90971687526fffffffffffffffffffffffffffffffff95861660208801527001000000000000000000000000000000009094049094169285019290925267ffffffffffffffff80821660608601526801000000000000000090910416608084015260a083015260c082015260e0016103a0565b6103bc6107363660046155e8565b611a66565b60335460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016103a0565b6103bc610771366004615511565b611b4b565b610789610784366004615356565b611b57565b60405190151581526020016103a0565b6103d9611bb4565b6103bc6107af366004615544565b611bd9565b6103bc6107c2366004615605565b611cc4565b61046d7f98d0bb2de1c65f6d2cbc3401e3d5d5086bfe815cb57e521dafd0ebdbef6ee85c81565b6103bc6107fc3660046154d8565b611e1f565b6103bc61080f36600461563e565b611f43565b6103bc6108223660046155e8565b612051565b6103bc61083536600461555f565b612136565b61078961084836600461566a565b612144565b6103bc61085b3660046154d8565b6122b6565b6103bc61086e366004615356565b612357565b6108866108813660046155e8565b6123f9565b6040516103a091906156c7565b6108a66108a13660046155a1565b612426565b6040516103a091906156da565b6108bb612512565b6040516103a094939291906157b1565b6103bc6108d9366004615544565b61254e565b6103bc6108ec366004615356565b612600565b6103bc6108ff366004615511565b61276c565b6103bc610912366004615356565b612855565b6103bc610925366004615356565b612a22565b6103bc610938366004615356565b612bbe565b6103bc61094b366004615356565b612ca5565b61046d7f71840dc4906352362b0cdaf79870196c8e42acafade72d5d5a6d59291253ceb181565b60655473ffffffffffffffffffffffffffffffffffffffff8281166000908152607260205260408082205490517f87326a0c0000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff909116600482015284939192909116906387326a0c90602401608060405180830381865afa158015610a0e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a329190615809565b50919250505073ffffffffffffffffffffffffffffffffffffffff81163314610abc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f53656e646572206973206e6f74206f70657261746f72206d616e61676572000060448201526064015b60405180910390fd5b610ae8837f98d0bb2de1c65f6d2cbc3401e3d5d5086bfe815cb57e521dafd0ebdbef6ee85c606c612d59565b505050565b610afd8686868686866001612eeb565b505050505050565b60685460009060609070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16610b3e606c61384c565b915091509091565b336000908152606f6020526040902054610bbc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53656e646572206973206e6f7420474f5645524e414e43455f524f4c450000006044820152606401610ab3565b610be782827f77ae3b5d012484be69eeed881350adb3189b651fac6e88b31ddff30c833a8b7f613860565b5050565b336000908152606f6020526040902054610c61576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53656e646572206973206e6f7420474f5645524e414e43455f524f4c450000006044820152606401610ab3565b67ffffffffffffffff82811660008181526077602090815260409182902060030180547fffffffffffffffffffffffffffffffff00000000000000000000000000000000169486169485179055905192835290917f4e4c0afc3a2b327c2f061f8ff5190a491f1042ba8f292a887bab97840947b7a9910160405180910390a25050565b336000908152606f6020526040902054610d5a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53656e646572206973206e6f7420474f5645524e414e43455f524f4c450000006044820152606401610ab3565b606980547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff83169081179091556040519081527f94bc488f4d9a985dd5f9d11e8f0a614a62828888eb65b704a90fa852be937549906020015b60405180910390a150565b336000908152606f6020526040902054610e3e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53656e646572206973206e6f7420474f5645524e414e43455f524f4c450000006044820152606401610ab3565b606580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527f70016f37fc9a299f674d1e3083a27743406649810887ed947a79884b064d2de990602001610dbd565b610eb96139d5565b73ffffffffffffffffffffffffffffffffffffffff811660009081526074602052604090205415610f46576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f4f70657261746f7220616c7265616479206578697374730000000000000000006044820152606401610ab3565b73ffffffffffffffffffffffffffffffffffffffff811660009081526074602052604090207f71840dc4906352362b0cdaf79870196c8e42acafade72d5d5a6d59291253ceb19055610f99606e82613a56565b506040805173ffffffffffffffffffffffffffffffffffffffff83168152600060208201527f71840dc4906352362b0cdaf79870196c8e42acafade72d5d5a6d59291253ceb1918101919091527f797ca55fc7be0f65c71f10996f7a16f801094f8ae3811874afc5a39730772a4290606001610dbd565b60655473ffffffffffffffffffffffffffffffffffffffff8281166000908152607260205260408082205490517f87326a0c0000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff909116600482015284939192909116906387326a0c90602401608060405180830381865afa1580156110a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110cb9190615809565b50919250505073ffffffffffffffffffffffffffffffffffffffff81163314611150576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f53656e646572206973206e6f74206f70657261746f72206d616e6167657200006044820152606401610ab3565b610ae8837f77ae3b5d012484be69eeed881350adb3189b651fac6e88b31ddff30c833a8b7f6078613a78565b61118a848484846001613d5a565b50505050565b336000908152606f6020526040902054611206576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53656e646572206973206e6f7420474f5645524e414e43455f524f4c450000006044820152606401610ab3565b60668190556040518181527eec8eefea39d742ff523b872c1931ff4d509ab873041c5d6e237d5f0fc053f890602001610dbd565b600054610100900460ff161580801561125a5750600054600160ff909116105b806112745750303b158015611274575060005460ff166001145b611300576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610ab3565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055801561135e57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b611366613eda565b611371606e33613a56565b5061139d606a7f71840dc4906352362b0cdaf79870196c8e42acafade72d5d5a6d59291253ceb1613f79565b506113c9606a7f98d0bb2de1c65f6d2cbc3401e3d5d5086bfe815cb57e521dafd0ebdbef6ee85c613f79565b506113f5606a7f59a1c48e5837ad7a7f3dcedcbe129bf3249ec4fbf651fd4f5e2600ead39fe2f5613f79565b5061140c6104af6002670de0b6b3a76400006158bb565b61141b655af3107a4000611a66565b61142560f0610ce4565b61142f6002611bd9565b61143882610dc8565b611443606e33613f85565b5073ffffffffffffffffffffffffffffffffffffffff831660009081526074602052604090207f71840dc4906352362b0cdaf79870196c8e42acafade72d5d5a6d59291253ceb19055611497606e84613a56565b506040805173ffffffffffffffffffffffffffffffffffffffff85168152600060208201527f71840dc4906352362b0cdaf79870196c8e42acafade72d5d5a6d59291253ceb18183015290517f797ca55fc7be0f65c71f10996f7a16f801094f8ae3811874afc5a39730772a429181900360600190a18015610ae857600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498906020015b60405180910390a1505050565b336000908152606f60205260409020546115eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53656e646572206973206e6f7420474f5645524e414e43455f524f4c450000006044820152606401610ab3565b606880546fffffffffffffffffffffffffffffffff908116700100000000000000000000000000000000918416918202179091556040519081527fb6c040bb0324b47cbf9a620cce03b311e24597626a57322173d5d5465f739d2790602001610dbd565b336000908152606f60205260409020546116c5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53656e646572206973206e6f7420474f5645524e414e43455f524f4c450000006044820152606401610ab3565b607b80546fffffffffffffffffffffffffffffffff908116700100000000000000000000000000000000918416918202179091556040519081527fa425d7d9b858a4250625446e4504257053202ae93ba0d1dea68dce7ec87a05c590602001610dbd565b610be782826000613fa7565b610afd8686868686866000612eeb565b336000908152606f60205260409020546117bb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53656e646572206973206e6f7420474f5645524e414e43455f524f4c450000006044820152606401610ab3565b67ffffffffffffffff82811660009081526077602090815260409182902060030180546fffffffffffffffffffffffffffffffff16938516700100000000000000000000000000000000810294909417905590519182527f1bca1fb481202bb14258ce1030d54e9e7bafc8b696d96b9eb733826e58a3a030910160405180910390a15050565b336000908152606f60205260409020546118b7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53656e646572206973206e6f7420474f5645524e414e43455f524f4c450000006044820152606401610ab3565b6118e3817f77ae3b5d012484be69eeed881350adb3189b651fac6e88b31ddff30c833a8b7f6078614364565b50565b6118ee6139d5565b6118f86000614524565b565b60655473ffffffffffffffffffffffffffffffffffffffff8281166000908152607260205260408082205490517f87326a0c0000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff909116600482015284939192909116906387326a0c90602401608060405180830381865afa158015611991573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119b59190615809565b50919250505073ffffffffffffffffffffffffffffffffffffffff81163314611a3a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f53656e646572206973206e6f74206f70657261746f72206d616e6167657200006044820152606401610ab3565b610ae8837f77ae3b5d012484be69eeed881350adb3189b651fac6e88b31ddff30c833a8b7f6078612d59565b336000908152606f6020526040902054611adc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53656e646572206973206e6f7420474f5645524e414e43455f524f4c450000006044820152606401610ab3565b606880547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff83169081179091556040519081527f01eb821dd596243f2f8c5f6c7478e281b855ac12a9f4be2c486cb2778a0bb81e90602001610dbd565b610be782826001613fa7565b73ffffffffffffffffffffffffffffffffffffffff81166000908152606d6020526040812054151580611bae575073ffffffffffffffffffffffffffffffffffffffff821660009081526079602052604090205415155b92915050565b607b546000906060906fffffffffffffffffffffffffffffffff16610b3e607861384c565b336000908152606f6020526040902054611c4f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53656e646572206973206e6f7420474f5645524e414e43455f524f4c450000006044820152606401610ab3565b606980547fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff166801000000000000000067ffffffffffffffff8416908102919091179091556040519081527f28312bbddd51eea4439db773218c441a4057f6ed285c642a569f1dcdba1cc04790602001610dbd565b336000908152606f6020526040902054611d3a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53656e646572206973206e6f7420474f5645524e414e43455f524f4c450000006044820152606401610ab3565b67ffffffffffffffff8416600090815260776020526040902081611dba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f5365636f6e64732070657220626c6f636b2063616e6e6f7420626520300000006044820152606401610ab3565b8381556001810183905560028101829055604080518581526020810185905290810183905267ffffffffffffffff8616907ffd97af399d19e6be9256c99c8e52b1809cdbc4dc96816739612b6fd4e6d940b09060600160405180910390a25050505050565b336000908152606f6020526040902054611e95576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53656e646572206973206e6f7420474f5645524e414e43455f524f4c450000006044820152606401610ab3565b6065546040517fa2e7e44100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301526fffffffffffffffffffffffffffffffff841660248301529091169063a2e7e441906044016020604051808303816000875af1158015611f1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ae891906158cf565b336000908152606f6020526040902054611fb9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53656e646572206973206e6f7420474f5645524e414e43455f524f4c450000006044820152606401610ab3565b6065546040517fad9e91ee0000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff841660048201526024810183905273ffffffffffffffffffffffffffffffffffffffff9091169063ad9e91ee90604401600060405180830381600087803b15801561203d57600080fd5b505af1158015610afd573d6000803e3d6000fd5b336000908152606f60205260409020546120c7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53656e646572206973206e6f7420474f5645524e414e43455f524f4c450000006044820152606401610ab3565b607b80547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff83169081179091556040519081527f3c123a1bb22d50819d69fdf807dc3a338b33bb1089acd51636778324836af17d90602001610dbd565b61118a848484846000613d5a565b600080836121775767ffffffffffffffff8087166000908152607a6020908152604080832093891683529290522061219e565b67ffffffffffffffff80871660009081526076602090815260408083209389168352929052205b600381015473ffffffffffffffffffffffffffffffffffffffff85166000908152600283016020526040812092935067ffffffffffffffff90911691908661221057815470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16600114612260565b67ffffffffffffffff89166000908152607760205260409020600301548254700100000000000000000000000000000000918290046fffffffffffffffffffffffffffffffff9081169290910416145b90508015801561227a57508267ffffffffffffffff164311155b806122a9575067ffffffffffffffff83161580156122a95750600384015468010000000000000000900460ff16155b9998505050505050505050565b336000908152606f602052604090205461232c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53656e646572206973206e6f7420474f5645524e414e43455f524f4c450000006044820152606401610ab3565b610be782827f98d0bb2de1c65f6d2cbc3401e3d5d5086bfe815cb57e521dafd0ebdbef6ee85c613860565b336000908152606f60205260409020546123cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53656e646572206973206e6f7420474f5645524e414e43455f524f4c450000006044820152606401610ab3565b6118e3817f98d0bb2de1c65f6d2cbc3401e3d5d5086bfe815cb57e521dafd0ebdbef6ee85c606c614364565b6fffffffffffffffffffffffffffffffff81166000908152607360205260409020606090611bae9061384c565b6060607c6000838152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b8282101561250757838290600052602060002001805461247a906158e8565b80601f01602080910402602001604051908101604052809291908181526020018280546124a6906158e8565b80156124f35780601f106124c8576101008083540402835291602001916124f3565b820191906000526020600020905b8154815290600101906020018083116124d657829003601f168201915b50505050508152602001906001019061245b565b505050509050919050565b606080606080612522606c61384c565b61252c606e61384c565b612536607061384c565b612540607861384c565b935093509350935090919293565b336000908152606f60205260409020546125c4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53656e646572206973206e6f7420474f5645524e414e43455f524f4c450000006044820152606401610ab3565b67ffffffffffffffff811660678190556040517fcaf46ba335d93b98398af7142ea3e362a6b8e91c57da6bf1e8a704f86374dde090600090a250565b60655473ffffffffffffffffffffffffffffffffffffffff8281166000908152607260205260408082205490517f87326a0c0000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff909116600482015284939192909116906387326a0c90602401608060405180830381865afa158015612697573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126bb9190615809565b50919250505073ffffffffffffffffffffffffffffffffffffffff81163314612740576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f53656e646572206973206e6f74206f70657261746f72206d616e6167657200006044820152606401610ab3565b610ae8837f98d0bb2de1c65f6d2cbc3401e3d5d5086bfe815cb57e521dafd0ebdbef6ee85c606c613a78565b336000908152606f60205260409020546127e2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53656e646572206973206e6f7420474f5645524e414e43455f524f4c450000006044820152606401610ab3565b67ffffffffffffffff82811660008181526077602052604080822060040180547fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000169486169485179055517fbbfa9310306e8a8485d109f8be6b0a808473ce55d2e94b8ca3447c9ddb2854b49190a35050565b336000908152606f60205260409020546128cb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53656e646572206973206e6f7420474f5645524e414e43455f524f4c450000006044820152606401610ab3565b73ffffffffffffffffffffffffffffffffffffffff811660009081526074602052604090205415612958576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f4f70657261746f7220616c7265616479206578697374730000000000000000006044820152606401610ab3565b73ffffffffffffffffffffffffffffffffffffffff811660009081526074602052604090207f59a1c48e5837ad7a7f3dcedcbe129bf3249ec4fbf651fd4f5e2600ead39fe2f590556129ab607082613a56565b506040805173ffffffffffffffffffffffffffffffffffffffff83168152600060208201527f59a1c48e5837ad7a7f3dcedcbe129bf3249ec4fbf651fd4f5e2600ead39fe2f5918101919091527f797ca55fc7be0f65c71f10996f7a16f801094f8ae3811874afc5a39730772a4290606001610dbd565b336000908152606f6020526040902054612a98576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f53656e646572206973206e6f7420474f5645524e414e43455f524f4c450000006044820152606401610ab3565b73ffffffffffffffffffffffffffffffffffffffff81166000908152607460205260409020547f59a1c48e5837ad7a7f3dcedcbe129bf3249ec4fbf651fd4f5e2600ead39fe2f514612b46576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f4f70657261746f72206973206e6f742061756469746f720000000000000000006044820152606401610ab3565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260746020526040812055612b77607082613f85565b5060405173ffffffffffffffffffffffffffffffffffffffff821681527f80c0b871b97b595b16a7741c1b06fed0c6f6f558639f18ccbce50724325dc40d90602001610dbd565b612bc66139d5565b73ffffffffffffffffffffffffffffffffffffffff81166000908152607460205260409020547f71840dc4906352362b0cdaf79870196c8e42acafade72d5d5a6d59291253ceb114612c74576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4f70657261746f72206973206e6f7420676f7665726e6f7200000000000000006044820152606401610ab3565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260746020526040812055612b77606e82613f85565b612cad6139d5565b73ffffffffffffffffffffffffffffffffffffffff8116612d50576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610ab3565b6118e381614524565b73ffffffffffffffffffffffffffffffffffffffff83166000908152607460205260409020548214612e0d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4f70657261746f7220646f6573206e6f7420706572666f726d2074686520726560448201527f7175657374656420726f6c6500000000000000000000000000000000000000006064820152608401610ab3565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600182016020526040902054612e9b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f4f70657261746f7220697320616c72656164792064697361626c6564000000006044820152606401610ab3565b612ea5838261459b565b60405173ffffffffffffffffffffffffffffffffffffffff841681527f23cd406c7cafe6d88c3f1c1cc16e438745a4236aec25906be2046ca16c36bd1e90602001611568565b8015612f9257336000908152606d6020526040902054612f8d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f53656e646572206973206e6f7420424c4f434b5f53504543494d454e5f50524f60448201527f44554345525f524f4c45000000000000000000000000000000000000000000006064820152608401610ab3565b61302e565b3360009081526079602052604090205461302e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f53656e646572206973206e6f7420424c4f434b5f524553554c545f50524f445560448201527f4345525f524f4c450000000000000000000000000000000000000000000000006064820152608401610ab3565b67ffffffffffffffff8088166000908152607760205260408120600481015490921690036130b8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f496e76616c696420636861696e204944000000000000000000000000000000006044820152606401610ab3565b60048101546130d19067ffffffffffffffff168861593b565b67ffffffffffffffff1615613142576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f496e76616c696420626c6f636b206865696768740000000000000000000000006044820152606401610ab3565b6000826131745767ffffffffffffffff808a166000908152607a60209081526040808320938c1683529290522061319b565b67ffffffffffffffff808a166000908152607660209081526040808320938c168352929052205b6003810154336000908152600283016020526040812092935067ffffffffffffffff90911691908290036131de576131d98b8b8b8b88888b886146e6565b613757565b8167ffffffffffffffff16431115613252576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f53657373696f6e207375626d697373696f6e73206861766520636c6f736564006044820152606401610ab3565b600384015481546fffffffffffffffffffffffffffffffff7001000000000000000000000000000000009283900481169290910416106132ee576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f4d6178207375626d697373696f6e73206c696d697420657863656564656400006044820152606401610ab3565b6000898152602084905260409020815460018201906fffffffffffffffffffffffffffffffff161561346c5760005b815481101561346657600083600001600084848154811061334057613340615962565b90600052602060002001548152602001908152602001600020905060005b8154811015613451573373ffffffffffffffffffffffffffffffffffffffff1682828154811061339057613390615962565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff160361343f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603660248201527f4f70657261746f7220616c7265616479207375626d697474656420666f72207460448201527f68652070726f766964656420626c6f636b2068617368000000000000000000006064820152608401610ab3565b8061344981615991565b91505061335e565b5050808061345e90615991565b91505061331d565b50613647565b606554336000908152607260205260408082205490517f4c4a17090000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff90911660048201529091829173ffffffffffffffffffffffffffffffffffffffff90911690634c4a1709906024016040805180830381865afa158015613500573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061352491906159c9565b915091508861354757607b546fffffffffffffffffffffffffffffffff16613571565b60685470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff165b6fffffffffffffffffffffffffffffffff16826fffffffffffffffffffffffffffffffff1610156135fe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f496e73756666696369656e746c79207374616b656420746f207375626d6974006044820152606401610ab3565b61360881836159f8565b85547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff9190911617855550505b60008a815260208390526040902081541561368057805460000361367b578154600181018355600083815260209020018b90555b6136ad565b600180870180548083018255600091825260208083209091018f9055845492830185558482529020018b90555b80546001810182556000828152602090200180547fffffffffffffffffffffffff0000000000000000000000000000000000000000163317905583546fffffffffffffffffffffffffffffffff7001000000000000000000000000000000009091041684601061371c83615a2c565b91906101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff160217905550505050505b6000888152607c6020908152604082208054600181018255908352912061378091018888615263565b5084156137e55780546040517f57b0cb34d2ff9ed661f8b3c684aaee6cbf0bda5da02f4044205556817fa8e76c916137d8918e918e918e918e918e918e916fffffffffffffffffffffffffffffffff90911690615a5b565b60405180910390a161383f565b80546040517f8741f5bf89731b15f24deb1e84e2bbd381947f009ee378a2daa15ed8abfb948591613836918e918e918e918e918e918e916fffffffffffffffffffffffffffffffff90911690615a5b565b60405180910390a15b5050505050505050505050565b6060600061385983614c6a565b9392505050565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260746020526040902054156138ed576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f4f70657261746f7220616c7265616479206578697374730000000000000000006044820152606401610ab3565b73ffffffffffffffffffffffffffffffffffffffff831660009081526074602090815260408083208490556072825280832080547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff871690811790915583526073909152902061396f9084613a56565b506040805173ffffffffffffffffffffffffffffffffffffffff851681526fffffffffffffffffffffffffffffffff841660208201529081018290527f797ca55fc7be0f65c71f10996f7a16f801094f8ae3811874afc5a39730772a4290606001611568565b60335473ffffffffffffffffffffffffffffffffffffffff1633146118f8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ab3565b60006138598373ffffffffffffffffffffffffffffffffffffffff8416614cc6565b73ffffffffffffffffffffffffffffffffffffffff83166000908152607460205260409020548214613b2c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4f70657261746f7220646f6573206e6f7420706572666f726d2074686520726560448201527f7175657374656420726f6c6500000000000000000000000000000000000000006064820152608401610ab3565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260018201602052604090205415613bbb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4f70657261746f7220697320616c726561647920656e61626c656400000000006044820152606401610ab3565b73ffffffffffffffffffffffffffffffffffffffff83166000908152607260205260409020546fffffffffffffffffffffffffffffffff16613bfd8285613a56565b506fffffffffffffffffffffffffffffffff808216600090815260756020526040812080549092169190613c3083615a2c565b82546101009290920a6fffffffffffffffffffffffffffffffff818102199093169183160217909155828116600090815260756020526040902054166001039050613d0b576065546040517fedff4b610000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff8316600482015273ffffffffffffffffffffffffffffffffffffffff9091169063edff4b6190602401600060405180830381600087803b158015613cf257600080fd5b505af1158015613d06573d6000803e3d6000fd5b505050505b60405173ffffffffffffffffffffffffffffffffffffffff851681527f9e532d260bd7dde07708a6b1f7c64042546243d79bac23514cd74fcfc1a01fe49060200160405180910390a150505050565b33600090815260716020526040902054613dd0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f53656e646572206973206e6f742041554449544f525f524f4c450000000000006044820152606401610ab3565b600081613e025767ffffffffffffffff8087166000908152607a60209081526040808320938916835292905220613e29565b67ffffffffffffffff80871660009081526076602090815260408083209389168352929052205b600381015490915068010000000000000000900460ff16613ecc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53657373696f6e206d7573742062652066696e616c697a6564206265666f726560448201527f20617564697400000000000000000000000000000000000000000000000000006064820152608401610ab3565b610afd818787878787614d15565b600054610100900460ff16613f71576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610ab3565b6118f86150d0565b60006138598383614cc6565b60006138598373ffffffffffffffffffffffffffffffffffffffff8416615170565b600081613fd95767ffffffffffffffff8085166000908152607a60209081526040808320938716835292905220614000565b67ffffffffffffffff80851660009081526076602090815260408083209387168352929052205b600381015490915067ffffffffffffffff1643811061407b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f53657373696f6e206e6f74207061737420646561646c696e65000000000000006044820152606401610ab3565b600382015468010000000000000000900460ff16156140f6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f53657373696f6e2063616e6e6f742062652066696e616c697a656400000000006044820152606401610ab3565b8067ffffffffffffffff1660000361416a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f53657373696f6e206e6f742073746172746564000000000000000000000000006044820152606401610ab3565b6000808080806001870181805b82548110156142355782818154811061419257614192615962565b6000918252602080832090910154808352908c905260408220909350905b6001820154811015614220578160010181815481106141d1576141d1615962565b6000918252602080832090910154808352908490526040909120549099506141f9818c615aee565b9a508881111561420d578098508497508996505b508061421881615991565b9150506141b0565b5050808061422d90615991565b915050614177565b5060695468010000000000000000900467ffffffffffffffff16851080159061427b57506066548761426f670de0b6b3a764000088615b06565b61427991906158bb565b115b156142935761428e898d8d87878f614d15565b614321565b89156142df5760405167ffffffffffffffff8c811682528d16907f8340aa7a5b37153230f8b64fa66f25c843e5002c60e63a25db6a9195005ccabd9060200160405180910390a2614321565b60405167ffffffffffffffff8c811682528d16907f31d16d882c6405d327fa305ecf0d52b45154868e0828822533fd2547f4b21a759060200160405180910390a25b505050600390950180547fffffffffffffffffffffffffffffffffffffffffffffff00000000000000000016680100000000000000001790555050505050505050565b73ffffffffffffffffffffffffffffffffffffffff83166000908152607460205260409020548214614418576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f4f70657261746f7220646f6573206e6f7420706572666f726d2074686520726560448201527f7175657374656420726f6c6500000000000000000000000000000000000000006064820152608401610ab3565b73ffffffffffffffffffffffffffffffffffffffff831660009081526001820160205260409020541561444f5761444f838261459b565b73ffffffffffffffffffffffffffffffffffffffff83166000908152607260209081526040808320546fffffffffffffffffffffffffffffffff1683526073909152902061449d9084613f85565b5073ffffffffffffffffffffffffffffffffffffffff8316600081815260726020908152604080832080547fffffffffffffffffffffffffffffffff00000000000000000000000000000000169055607482528083209290925590519182527f80c0b871b97b595b16a7741c1b06fed0c6f6f558639f18ccbce50724325dc40d9101611568565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6145a58183613f85565b5073ffffffffffffffffffffffffffffffffffffffff82166000908152607260209081526040808320546fffffffffffffffffffffffffffffffff908116808552607590935290832080549293929091169161460083615b43565b82546101009290920a6fffffffffffffffffffffffffffffffff81810219909316918316021790915582811660009081526075602052604081205490911690039050610ae8576065546040517fad9e91ee0000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff8316600482015243602482015273ffffffffffffffffffffffffffffffffffffffff9091169063ad9e91ee90604401600060405180830381600087803b1580156146c957600080fd5b505af11580156146dd573d6000803e3d6000fd5b50505050505050565b600383015468010000000000000000900460ff1615614761576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f53657373696f6e207375626d697373696f6e73206861766520636c6f736564006044820152606401610ab3565b6000846002015460675486600101544361477b9190615b8d565b6147859190615b06565b61478f91906158bb565b855461479b9190615aee565b60038601549091506000906fffffffffffffffffffffffffffffffff168210156147c65760006147e7565b60038601546147e7906fffffffffffffffffffffffffffffffff1683615b8d565b90508867ffffffffffffffff16811115801561482d5750600386015461481f906fffffffffffffffffffffffffffffffff1683615aee565b8967ffffffffffffffff1611155b6148b9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f426c6f636b20686569676874206973206f7574206f6620626f756e647320666f60448201527f72206c6976652073796e630000000000000000000000000000000000000000006064820152608401610ab3565b6069546148d09067ffffffffffffffff1643615aee565b6003860180547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff92909216919091179055606554336000908152607260205260408082205490517f4c4a17090000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff90911660048201529091829173ffffffffffffffffffffffffffffffffffffffff90911690634c4a1709906024016040805180830381865afa15801561499f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149c391906159c9565b91509150856149e657607b546fffffffffffffffffffffffffffffffff16614a10565b60685470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff165b6fffffffffffffffffffffffffffffffff16826fffffffffffffffffffffffffffffffff161015614a9d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f496e73756666696369656e746c79207374616b656420746f207375626d6974006044820152606401610ab3565b614aa781836159f8565b85546fffffffffffffffffffffffffffffffff9182167fffffffffffffffffffffffffffffffff00000000000000000000000000000000909116178655600188810180548083018255600091825260208083209091018e90558d82528a8152604080832080850180548087018255908552838520018f90558e8452808352908320805494850181558352912090910180547fffffffffffffffffffffffff000000000000000000000000000000000000000016331790558654909170010000000000000000000000000000000090910416866010614b8483615a2c565b91906101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff160217905550508615614c1057600388015460405167ffffffffffffffff9182168152818e16918f16907f49caa59dfff8e73f72d249149e72487a67c49cf76549aed997c63963b436c3c29060200160405180910390a3614c5b565b600388015460405167ffffffffffffffff9182168152818e16918f16907f06a773d98907981dde2b75694bea53d9542cb1434717f5c66e699dee821a73249060200160405180910390a35b50505050505050505050505050565b606081600001805480602002602001604051908101604052809291908181526020018280548015614cba57602002820191906000526020600020905b815481526020019060010190808311614ca6575b50505050509050919050565b6000818152600183016020526040812054614d0d57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611bae565b506000611bae565b60008381526020878152604080832085845290915281208054828167ffffffffffffffff811115614d4857614d48615ba4565b604051908082528060200260200182016040528015614d71578160200160208202803683370190505b50905060008267ffffffffffffffff811115614d8f57614d8f615ba4565b604051908082528060200260200182016040528015614db8578160200160208202803683370190505b509050600060028c01815b85811015614e4257816000888381548110614de057614de0615962565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902054614e2e906fffffffffffffffffffffffffffffffff16846159f8565b925080614e3a81615991565b915050614dc3565b5060005b85811015614f6c57868181548110614e6057614e60615962565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff1680835284825260408084206072909352909220548751929a5090916fffffffffffffffffffffffffffffffff90911690879084908110614ec657614ec6615962565b6fffffffffffffffffffffffffffffffff9283166020918202929092010152606854825486831692614efb9281169116615b06565b614f0591906158bb565b858381518110614f1757614f17615962565b6fffffffffffffffffffffffffffffffff92831660209182029290920101528154700100000000000000000000000000000000900416600103614f5957600081555b5080614f6481615991565b915050614e46565b506065546040517f605a501700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091169063605a501790614fc59087908790600401615c15565b600060405180830381600087803b158015614fdf57600080fd5b505af1158015614ff3573d6000803e3d6000fd5b50505050871561505257898b67ffffffffffffffff168d67ffffffffffffffff167ff05ac779af1ec75a7b2fbe9415b33a67c00294a121786f7ce2eb3f92e4a6424a8c60405161504591815260200190565b60405180910390a46150a3565b898b67ffffffffffffffff168d67ffffffffffffffff167f93dcf9329a330cb95723152c05719560f2fbd50e215c542854b27acc80c9108d8c60405161509a91815260200190565b60405180910390a45b60008a815260208e905260408120906150bf6001830182615305565b505050505050505050505050505050565b600054610100900460ff16615167576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610ab3565b6118f833614524565b60008181526001830160205260408120548015615259576000615194600183615b8d565b85549091506000906151a890600190615b8d565b905081811461520d5760008660000182815481106151c8576151c8615962565b90600052602060002001549050808760000184815481106151eb576151eb615962565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061521e5761521e615c43565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050611bae565b6000915050611bae565b82805461526f906158e8565b90600052602060002090601f01602090048101928261529157600085556152f5565b82601f106152c8578280017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008235161785556152f5565b828001600101855582156152f5579182015b828111156152f55782358255916020019190600101906152da565b5061530192915061531f565b5090565b50805460008255906000526020600020908101906118e391905b5b808211156153015760008155600101615320565b73ffffffffffffffffffffffffffffffffffffffff811681146118e357600080fd5b60006020828403121561536857600080fd5b813561385981615334565b803567ffffffffffffffff8116811461538b57600080fd5b919050565b60008060008060008060a087890312156153a957600080fd5b6153b287615373565b95506153c060208801615373565b94506040870135935060608701359250608087013567ffffffffffffffff808211156153eb57600080fd5b818901915089601f8301126153ff57600080fd5b81358181111561540e57600080fd5b8a602082850101111561542057600080fd5b6020830194508093505050509295509295509295565b600081518084526020808501945080840160005b8381101561547c57815173ffffffffffffffffffffffffffffffffffffffff168752958201959082019060010161544a565b509495945050505050565b6fffffffffffffffffffffffffffffffff831681526040602082015260006154b26040830184615436565b949350505050565b6fffffffffffffffffffffffffffffffff811681146118e357600080fd5b600080604083850312156154eb57600080fd5b82356154f681615334565b91506020830135615506816154ba565b809150509250929050565b6000806040838503121561552457600080fd5b61552d83615373565b915061553b60208401615373565b90509250929050565b60006020828403121561555657600080fd5b61385982615373565b6000806000806080858703121561557557600080fd5b61557e85615373565b935061558c60208601615373565b93969395505050506040820135916060013590565b6000602082840312156155b357600080fd5b5035919050565b600080604083850312156155cd57600080fd5b82356155d881615334565b9150602083013561550681615334565b6000602082840312156155fa57600080fd5b8135613859816154ba565b6000806000806080858703121561561b57600080fd5b61562485615373565b966020860135965060408601359560600135945092505050565b6000806040838503121561565157600080fd5b823561565c816154ba565b946020939093013593505050565b6000806000806080858703121561568057600080fd5b61568985615373565b935061569760208601615373565b9250604085013580151581146156ac57600080fd5b915060608501356156bc81615334565b939692955090935050565b6020815260006138596020830184615436565b6000602080830181845280855180835260408601915060408160051b87010192508387016000805b838110156157a3577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc089870301855282518051808852835b81811015615755578281018a01518982018b0152890161573a565b8181111561576557848a838b0101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01696909601870195509386019391860191600101615702565b509398975050505050505050565b6080815260006157c46080830187615436565b82810360208401526157d68187615436565b905082810360408401526157ea8186615436565b905082810360608401526157fe8185615436565b979650505050505050565b6000806000806080858703121561581f57600080fd5b845161582a81615334565b602086015190945061583b816154ba565b604086015190935061584c816154ba565b60608601519092506156bc816154ba565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000826158ca576158ca61585d565b500490565b6000602082840312156158e157600080fd5b5051919050565b600181811c908216806158fc57607f821691505b602082108103615935577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b600067ffffffffffffffff808416806159565761595661585d565b92169190910692915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036159c2576159c261588c565b5060010190565b600080604083850312156159dc57600080fd5b82516159e7816154ba565b6020840151909250615506816154ba565b60006fffffffffffffffffffffffffffffffff808316818516808303821115615a2357615a2361588c565b01949350505050565b60006fffffffffffffffffffffffffffffffff808316818103615a5157615a5161588c565b6001019392505050565b600067ffffffffffffffff808a16835280891660208401525086604083015285606083015260c060808301528360c0830152838560e0840137600060e0858401015260e07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f86011683010190506fffffffffffffffffffffffffffffffff831660a083015298975050505050505050565b60008219821115615b0157615b0161588c565b500190565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615615b3e57615b3e61588c565b500290565b60006fffffffffffffffffffffffffffffffff821680615b6557615b6561588c565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0192915050565b600082821015615b9f57615b9f61588c565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600081518084526020808501945080840160005b8381101561547c5781516fffffffffffffffffffffffffffffffff1687529582019590820190600101615be7565b604081526000615c286040830185615bd3565b8281036020840152615c3a8185615bd3565b95945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea264697066735822122046e0a8f3fd2d2197b633d9c2b5872f97478a01643657c19d9bfe2b2600804a8964736f6c634300080d0033

Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
Block Uncle Number Difficulty Gas Used Reward
Loading