ETH Price: $3,712.48 (+4.27%)
Gas: 1.82 Gwei

Contract

0xFFbBdAd0241D5eB38ccE77C4E21322B42b2D9212
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

Advanced mode:

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
AxiomV2Query

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 100000 runs

Other Settings:
paris EvmVersion
File 1 of 22 : AxiomV2Query.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import { AccessControlUpgradeable } from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import { Address } from "@openzeppelin/contracts/utils/Address.sol";

import { IAxiomV2HeaderVerifier } from "../interfaces/query/IAxiomV2HeaderVerifier.sol";
import {
    IAxiomV2Query,
    AXIOM_QUERY_STATE_INACTIVE,
    AXIOM_QUERY_STATE_ACTIVE,
    AXIOM_QUERY_STATE_FULFILLED,
    AXIOM_QUERY_STATE_PAID
} from "../interfaces/query/IAxiomV2Query.sol";
import { IAxiomV2Client } from "../interfaces/client/IAxiomV2Client.sol";

import { AxiomAccess } from "../libraries/access/AxiomAccess.sol";
import {
    MAX_DEPOSIT_SIZE,
    MAX_PROOF_VERIFICATION_GAS,
    MAX_AXIOM_QUERY_FEE,
    VERSION
} from "../libraries/configuration/AxiomV2Configuration.sol";

/// @title  AxiomV2Query
/// @notice Axiom smart contract that verifies AxiomV2 queries.
/// @dev    Is a UUPS upgradeable contract.
contract AxiomV2Query is IAxiomV2Query, AxiomAccess, UUPSUpgradeable {
    using Address for address payable;

    /// @dev address of deployed Axiom header verifier
    address public axiomHeaderVerifierAddress;

    /// @dev address of deployed ZKP verifier for queries
    address public verifierAddress;

    /// @dev the set of `aggregateVkeyHashes` accepted for proof fulfillment for any query
    mapping(bytes32 => bool) public aggregateVkeyHashes;

    /// @dev `perQueryAggregateVkeyHashes[querySchema][target][aggregateVkeyHash]` is true
    ///      if `aggregateVkeyHash` is valid for queries of type `querySchema` with callback `target`
    mapping(bytes32 => mapping(address => mapping(bytes32 => bool))) public perQueryAggregateVkeyHashes;

    /// @dev `perQueryProvers[querySchema][target][prover]` is true
    ///      if `prover` is allowed to fulfill queries of type `querySchema` with callback `target`
    mapping(bytes32 => mapping(address => mapping(address => bool))) public perQueryProvers;

    /// @dev the number of blocks after which a query is eligible for refund
    uint32 public queryDeadlineInterval;

    /// @dev the gas allocated for proof verification
    uint32 public proofVerificationGas;

    /// @dev the fee charged for Axiom proofs
    uint256 public axiomQueryFee;

    /// @dev the minimum allowed maxFeePerGas in a query
    uint64 public minMaxFeePerGas;

    /// @dev the maximum allowed queryDeadlineInterval, cannot be changed after initialization
    uint32 public maxQueryDeadlineInterval;

    /// @dev `queries[queryId]` stores the metadata for an on-chain query
    mapping(uint256 => AxiomQueryMetadata) public queries;

    /// @dev `balances[addr]` stores the amount of unescrowed wei deposited by `addr`
    mapping(address => uint256) public balances;

    /// @custom:oz-upgrades-unsafe-allow constructor
    /// @notice Prevents the implementation contract from being initialized outside of the upgradeable proxy.
    constructor() {
        _disableInitializers();
    }

    /// @dev    Initialize the contract.
    /// @param  init the initialization parameters
    function initialize(AxiomV2QueryInit calldata init) public initializer {
        __UUPSUpgradeable_init();
        __AxiomAccess_init_unchained();

        if (init.timelock == address(0)) {
            revert TimelockAddressIsZero();
        }
        if (init.guardian == address(0)) {
            revert GuardianAddressIsZero();
        }
        if (init.unfreeze == address(0)) {
            revert UnfreezeAddressIsZero();
        }

        _updateAxiomHeaderVerifierAddress(init.axiomHeaderVerifierAddress);
        _updateVerifierAddress(init.verifierAddress);

        for (uint256 i; i < init.aggregateVkeyHashes.length;) {
            _addAggregateVkeyHash(init.aggregateVkeyHashes[i]);
            unchecked {
                ++i;
            }
        }

        maxQueryDeadlineInterval = init.maxQueryDeadlineInterval;
        _updateQueryDeadlineInterval(init.queryDeadlineInterval);
        _updateProofVerificationGas(init.proofVerificationGas);
        _updateAxiomQueryFee(init.axiomQueryFee);
        _updateMinMaxFeePerGas(init.minMaxFeePerGas);

        _grantRole(DEFAULT_ADMIN_ROLE, init.timelock);
        _grantRole(TIMELOCK_ROLE, init.timelock);
        _grantRole(GUARDIAN_ROLE, init.guardian);
        _grantRole(UNFREEZE_ROLE, init.unfreeze);

        address prover;
        for (uint256 i; i < init.proverAddresses.length;) {
            prover = init.proverAddresses[i];
            if (prover == address(0)) {
                revert ProverAddressIsZero();
            }
            _grantRole(PROVER_ROLE, prover);
            unchecked {
                ++i;
            }
        }
    }

    /// @notice Updates the address of the IAxiomV2HeaderVerifier contract used to validate blockhashes, governed by a 'timelock'.
    /// @param  _axiomHeaderVerifierAddress the new address
    function updateAxiomHeaderVerifierAddress(address _axiomHeaderVerifierAddress) external onlyRole(TIMELOCK_ROLE) {
        _updateAxiomHeaderVerifierAddress(_axiomHeaderVerifierAddress);
    }

    /// @notice Updates the address of the query verifier contract, governed by a 'timelock'.
    /// @param  _verifierAddress the new address
    function updateVerifierAddress(address _verifierAddress) external onlyRole(TIMELOCK_ROLE) {
        _updateVerifierAddress(_verifierAddress);
    }

    /// @notice Add a new `aggregateVkeyHash` which can be used to fulfill queries.
    /// @param  _aggregateVkeyHash the new `aggregateVkeyHash`
    function addAggregateVkeyHash(bytes32 _aggregateVkeyHash) external onlyRole(TIMELOCK_ROLE) {
        _addAggregateVkeyHash(_aggregateVkeyHash);
    }

    /// @notice Remove an existing `aggregateVkeyHash` which can be used to fulfill queries.
    /// @param  _aggregateVkeyHash the `aggregateVkeyHash` to remove
    function removeAggregateVkeyHash(bytes32 _aggregateVkeyHash) external onlyRole(TIMELOCK_ROLE) {
        aggregateVkeyHashes[_aggregateVkeyHash] = false;
        emit RemoveAggregateVkeyHash(_aggregateVkeyHash);
    }

    /// @notice Updates the query deadline interval, governed by a 'timelock'.
    /// @param  _queryDeadlineInterval the new query deadline interval
    function updateQueryDeadlineInterval(uint32 _queryDeadlineInterval) external onlyRole(TIMELOCK_ROLE) {
        _updateQueryDeadlineInterval(_queryDeadlineInterval);
    }

    /// @notice Updates the proof verification gas, governed by a 'timelock'.
    /// @param  _proofVerificationGas the new proof verification gas
    function updateProofVerificationGas(uint32 _proofVerificationGas) external onlyRole(TIMELOCK_ROLE) {
        _updateProofVerificationGas(_proofVerificationGas);
    }

    /// @notice Updates the Axiom query fee, governed by a 'timelock'.
    /// @param  _axiomQueryFee the new Axiom query fee
    function updateAxiomQueryFee(uint256 _axiomQueryFee) external onlyRole(TIMELOCK_ROLE) {
        _updateAxiomQueryFee(_axiomQueryFee);
    }

    /// @notice Updates the minimum allowed maxFeePerGas in a query, governed by a 'timelock'.
    /// @param  _minMaxFeePerGas the new minimum allowed maxFeePerGas
    function updateMinMaxFeePerGas(uint64 _minMaxFeePerGas) external onlyRole(TIMELOCK_ROLE) {
        _updateMinMaxFeePerGas(_minMaxFeePerGas);
    }

    /// @notice Add allowed aggregateVkeyHash for a given query schema and target address
    /// @param querySchema The query schema
    /// @param target The callback address
    /// @param aggregateVkeyHash The aggregateVkeyHash to add
    function addPerQueryAggregateVkeyHash(bytes32 querySchema, address target, bytes32 aggregateVkeyHash)
        external
        onlyRole(TIMELOCK_ROLE)
    {
        perQueryAggregateVkeyHashes[querySchema][target][aggregateVkeyHash] = true;
        emit AddPerQueryAggregateVkeyHash(querySchema, target, aggregateVkeyHash);
    }

    /// @notice Remove allowed aggregateVkeyHash for a given query schema and target address
    /// @param querySchema The query schema
    /// @param target The callback address
    /// @param aggregateVkeyHash The aggregateVkeyHash to add
    function removePerQueryAggregateVkeyHash(bytes32 querySchema, address target, bytes32 aggregateVkeyHash)
        external
        onlyRole(TIMELOCK_ROLE)
    {
        perQueryAggregateVkeyHashes[querySchema][target][aggregateVkeyHash] = false;
        emit RemovePerQueryAggregateVkeyHash(querySchema, target, aggregateVkeyHash);
    }

    /// @dev Add allowed prover address for a given query schema and target address
    /// @param querySchema The query schema
    /// @param target The callback address
    /// @param prover The prover address
    function addPerQueryProver(bytes32 querySchema, address target, address prover) external onlyRole(TIMELOCK_ROLE) {
        perQueryProvers[querySchema][target][prover] = true;
        emit AddPerQueryProver(querySchema, target, prover);
    }

    /// @dev Remove allowed prover address for a given query schema and target address
    /// @param querySchema The query schema
    /// @param target The callback address
    /// @param prover The prover address
    function removePerQueryProver(bytes32 querySchema, address target, address prover)
        external
        onlyRole(TIMELOCK_ROLE)
    {
        perQueryProvers[querySchema][target][prover] = false;
        emit RemovePerQueryProver(querySchema, target, prover);
    }

    /// @inheritdoc IAxiomV2Query
    function sendQuery(
        uint64 sourceChainId,
        bytes32 dataQueryHash,
        AxiomV2ComputeQuery calldata computeQuery,
        AxiomV2Callback calldata callback,
        AxiomV2FeeData calldata feeData,
        bytes32 userSalt,
        address refundee,
        bytes calldata /* dataQuery */
    ) external payable onlyNotFrozen returns (uint256 queryId) {
        if (sourceChainId != IAxiomV2HeaderVerifier(axiomHeaderVerifierAddress).getSourceChainId()) {
            revert SourceChainIdDoesNotMatch();
        }

        if (refundee == address(0)) {
            refundee = msg.sender;
        }

        bytes32 queryHash;
        if (computeQuery.k == 0) {
            queryHash = keccak256(
                abi.encodePacked(VERSION, sourceChainId, dataQueryHash, computeQuery.k, computeQuery.resultLen)
            );
        } else {
            bytes memory encodedComputeQuerySchema = abi.encodePacked(
                computeQuery.k, computeQuery.resultLen, uint8(computeQuery.vkey.length), computeQuery.vkey
            );
            queryHash = keccak256(
                abi.encodePacked(
                    VERSION,
                    sourceChainId,
                    dataQueryHash,
                    encodedComputeQuerySchema,
                    uint32(computeQuery.computeProof.length),
                    computeQuery.computeProof
                )
            );
        }

        queryId = _computeQueryId(
            queryHash, keccak256(abi.encodePacked(callback.target, callback.extraData)), userSalt, refundee, msg.sender
        );
        _sendQuery(queryId, feeData.maxFeePerGas, feeData.callbackGasLimit, feeData.overrideAxiomQueryFee);

        emit QueryInitiatedOnchain(
            msg.sender, queryHash, queryId, userSalt, refundee, callback.target, callback.extraData
        );
    }

    /// @inheritdoc IAxiomV2Query
    function sendQueryWithIpfsData(
        bytes32 queryHash,
        bytes32 ipfsHash,
        AxiomV2Callback calldata callback,
        AxiomV2FeeData calldata feeData,
        bytes32 userSalt,
        address refundee
    ) external payable onlyNotFrozen returns (uint256 queryId) {
        if (refundee == address(0)) {
            refundee = msg.sender;
        }

        queryId = _computeQueryId(
            queryHash, keccak256(abi.encodePacked(callback.target, callback.extraData)), userSalt, refundee, msg.sender
        );
        _sendQuery(queryId, feeData.maxFeePerGas, feeData.callbackGasLimit, feeData.overrideAxiomQueryFee);

        emit QueryInitiatedWithIpfsData(
            msg.sender, queryHash, queryId, userSalt, ipfsHash, refundee, callback.target, callback.extraData
        );
    }

    /// @inheritdoc IAxiomV2Query
    function increaseQueryGas(
        uint256 queryId,
        uint64 newMaxFeePerGas,
        uint32 newCallbackGasLimit,
        uint256 overrideAxiomQueryFee
    ) external payable onlyNotFrozen {
        AxiomQueryMetadata storage queryMetadata = queries[queryId];
        if (queryMetadata.state != AXIOM_QUERY_STATE_ACTIVE) {
            revert CanOnlyIncreaseGasOnActiveQuery();
        }
        if (newMaxFeePerGas < minMaxFeePerGas) {
            revert MaxFeePerGasIsTooLow();
        }

        uint256 oldAmount = queryMetadata.payment;

        uint256 _axiomQueryFee = axiomQueryFee;
        if (overrideAxiomQueryFee > _axiomQueryFee) {
            _axiomQueryFee = overrideAxiomQueryFee;
        }
        uint256 newMaxQueryPri = _getMaxQueryPri(newMaxFeePerGas, newCallbackGasLimit, _axiomQueryFee);
        if (newMaxQueryPri <= oldAmount) {
            revert NewMaxQueryPriMustBeLargerThanPrevious();
        }
        uint256 increaseAmount;
        unchecked {
            // in this branch, we know that newMaxQueryPri > oldAmount
            increaseAmount = newMaxQueryPri - oldAmount;
        }
        if (msg.value < increaseAmount) {
            revert InsufficientFunds();
        }
        queryMetadata.payment = newMaxQueryPri;
        emit QueryGasIncreased(queryId, newMaxFeePerGas, newCallbackGasLimit, overrideAxiomQueryFee);

        if (msg.value > increaseAmount) {
            unchecked {
                // in this branch, we know that msg.value > increaseAmount
                _recordDeposit(msg.sender, msg.value - increaseAmount);
            }
        }
    }

    /// @inheritdoc IAxiomV2Query
    function fulfillQuery(
        IAxiomV2HeaderVerifier.MmrWitness calldata mmrWitness,
        bytes32[] calldata computeResults,
        bytes calldata proof,
        AxiomV2Callback calldata callback,
        AxiomV2QueryWitness calldata queryWitness
    ) external onlyNotFrozen {
        AxiomProofData memory proofData =
            _verifyResult(mmrWitness, proof, callback.target, keccak256(abi.encodePacked(computeResults)));

        uint256 queryId = _computeQueryId(
            queryWitness.queryHash,
            queryWitness.callbackHash,
            queryWitness.userSalt,
            queryWitness.refundee,
            queryWitness.caller
        );

        if (queryWitness.callbackHash != keccak256(abi.encodePacked(callback.target, callback.extraData))) {
            revert CallbackHashDoesNotMatchQueryWitness();
        }

        if (queryWitness.queryHash != proofData.queryHash) {
            revert QueryHashDoesNotMatchProof();
        }

        AxiomQueryMetadata storage queryMetadata = queries[queryId];
        if (queryMetadata.state != AXIOM_QUERY_STATE_ACTIVE) {
            revert CannotFulfillIfNotActive();
        }

        queryMetadata.payee = proofData.payee;
        queryMetadata.state = AXIOM_QUERY_STATE_FULFILLED;

        bool success;
        /// @dev re-entrancy protection:
        ///   we check and transition the query state before calling a client contract
        if (callback.target != address(0)) {
            bytes memory data = abi.encodeWithSelector(
                IAxiomV2Client.axiomV2Callback.selector,
                proofData.sourceChainId,
                queryWitness.caller,
                proofData.querySchema,
                queryId,
                computeResults,
                callback.extraData
            );

            /// @dev This checks that the callback is provided at least `callbackGasLimit` gas.
            ///      Factor of 64 / 63 accounts for the EIP-150 gas forwarding rule.
            ///      Additional 300 gas accounts for computation of the conditional branch.
            if (gasleft() - 300 <= queryMetadata.callbackGasLimit * 64 / 63) {
                revert InsufficientGasForCallback();
            }
            success = _callWithNoReturn(callback.target, queryMetadata.callbackGasLimit, data);
        }
        emit QueryFulfilled(queryId, proofData.payee, success);
    }

    /// @inheritdoc IAxiomV2Query
    function fulfillOffchainQuery(
        IAxiomV2HeaderVerifier.MmrWitness calldata mmrWitness,
        bytes32[] calldata computeResults,
        bytes calldata proof,
        AxiomV2Callback calldata callback,
        bytes32 userSalt
    ) external onlyNotFrozen {
        AxiomProofData memory proofData =
            _verifyResult(mmrWitness, proof, callback.target, keccak256(abi.encodePacked(computeResults)));

        uint256 queryId = _computeQueryId(
            proofData.queryHash,
            keccak256(abi.encodePacked(callback.target, callback.extraData)),
            userSalt,
            address(0),
            msg.sender
        );

        AxiomQueryMetadata storage queryMetadata = queries[queryId];
        if (queryMetadata.state != AXIOM_QUERY_STATE_INACTIVE) {
            revert CannotFulfillFromOffchainIfNotInactive();
        }

        if (proofData.payee != msg.sender) {
            revert OnlyPayeeCanFulfillOffchainQuery();
        }

        queryMetadata.state = AXIOM_QUERY_STATE_FULFILLED;

        bool success;
        /// @dev re-entrancy protection:
        ///   we check and transition the query state before calling a client contract
        if (callback.target != address(0)) {
            bytes memory data = abi.encodeWithSelector(
                IAxiomV2Client.axiomV2OffchainCallback.selector,
                proofData.sourceChainId,
                msg.sender,
                proofData.querySchema,
                queryId,
                computeResults,
                callback.extraData
            );
            success = _callWithNoReturn(callback.target, gasleft(), data);
        }
        emit OffchainQueryFulfilled(queryId, success);
    }

    /// @inheritdoc IAxiomV2Query
    function refundQuery(AxiomV2QueryWitness calldata queryWitness) external onlyNotFrozen {
        address refundee = queryWitness.refundee;
        uint256 queryId = _computeQueryId(
            queryWitness.queryHash, queryWitness.callbackHash, queryWitness.userSalt, refundee, queryWitness.caller
        );

        if (msg.sender != refundee) {
            revert CannotRefundIfNotRefundee();
        }

        AxiomQueryMetadata storage queryMetadata = queries[queryId];
        if (queryMetadata.state != AXIOM_QUERY_STATE_ACTIVE) {
            revert CannotRefundIfNotActive();
        }
        if (block.number <= queryMetadata.deadlineBlockNumber) {
            revert CannotRefundBeforeDeadline();
        }

        unchecked {
            // balances cannot overflow
            balances[refundee] += queryMetadata.payment;
        }

        delete queries[queryId];

        emit QueryRefunded(queryId, refundee);
    }

    /// @inheritdoc IAxiomV2Query
    function deposit(address payor) external payable onlyNotFrozen {
        if (payor == address(0)) {
            revert PayorAddressIsZero();
        }
        if (msg.value == 0) {
            revert DepositAmountIsZero();
        }
        _recordDeposit(payor, msg.value);
    }

    /// @inheritdoc IAxiomV2Query
    function unescrow(AxiomV2QueryWitness calldata queryWitness, uint256 amountUsed) external onlyNotFrozen {
        address refundee = queryWitness.refundee;
        uint256 queryId = _computeQueryId(
            queryWitness.queryHash, queryWitness.callbackHash, queryWitness.userSalt, refundee, queryWitness.caller
        );

        AxiomQueryMetadata storage queryMetadata = queries[queryId];
        if (queryMetadata.state != AXIOM_QUERY_STATE_FULFILLED) {
            revert QueryIsNotFulfilled();
        }
        uint256 payment = queryMetadata.payment;
        if (amountUsed > payment) {
            revert UnescrowAmountExceedsEscrowedAmount();
        }
        address payee = queryMetadata.payee;
        if (msg.sender != payee) {
            revert OnlyPayeeCanUnescrow();
        }

        queryMetadata.state = AXIOM_QUERY_STATE_PAID;

        unchecked {
            // in this branch, we know that amountUsed <= payment
            // in addition, balances cannot overflow
            balances[payee] += amountUsed;
            balances[refundee] += payment - amountUsed;
        }
        emit Unescrow(queryWitness.caller, queryId, payee, refundee, amountUsed);
    }

    /// @inheritdoc IAxiomV2Query
    function withdraw(uint256 amount, address payable payee) external {
        if (payee == address(0)) {
            revert PayeeAddressIsZero();
        }
        if (amount > balances[msg.sender]) {
            revert WithdrawalAmountExceedsFreeBalance();
        }
        if (amount == 0) {
            revert WithdrawalAmountIsZero();
        }

        unchecked {
            // in this branch, we know that amount <= balances[msg.sender]
            balances[msg.sender] -= amount;
        }
        payee.sendValue(amount);
        emit Withdraw(msg.sender, amount, payee);
    }

    /// @dev Update the address of the IAxiomV2HeaderVerifier contract used to validate blockhashes.
    /// @param  _axiomHeaderVerifierAddress the new address
    function _updateAxiomHeaderVerifierAddress(address _axiomHeaderVerifierAddress) internal {
        if (_axiomHeaderVerifierAddress == address(0)) {
            revert AxiomHeaderVerifierAddressIsZero();
        }
        axiomHeaderVerifierAddress = _axiomHeaderVerifierAddress;
        emit UpdateAxiomHeaderVerifierAddress(_axiomHeaderVerifierAddress);
    }

    /// @dev Update the address of the query verifier contract.
    /// @param  _verifierAddress the new address
    function _updateVerifierAddress(address _verifierAddress) internal {
        if (_verifierAddress == address(0)) {
            revert VerifierAddressIsZero();
        }
        verifierAddress = _verifierAddress;
        emit UpdateVerifierAddress(_verifierAddress);
    }

    /// @dev Add a new `aggregateVkeyHash` which can be used to fulfill queries.
    /// @param  _aggregateVkeyHash the new `aggregateVkeyHash`
    function _addAggregateVkeyHash(bytes32 _aggregateVkeyHash) internal {
        aggregateVkeyHashes[_aggregateVkeyHash] = true;
        emit AddAggregateVkeyHash(_aggregateVkeyHash);
    }

    /// @dev Update the query deadline interval.
    /// @param  _queryDeadlineInterval the new query deadline interval
    function _updateQueryDeadlineInterval(uint32 _queryDeadlineInterval) internal {
        if (_queryDeadlineInterval > maxQueryDeadlineInterval) {
            revert QueryDeadlineIntervalIsTooLarge();
        }
        queryDeadlineInterval = _queryDeadlineInterval;
        emit UpdateQueryDeadlineInterval(_queryDeadlineInterval);
    }

    /// @dev Update the proof verification gas.
    /// @param  _proofVerificationGas the new proof verification gas
    function _updateProofVerificationGas(uint32 _proofVerificationGas) internal {
        if (_proofVerificationGas > MAX_PROOF_VERIFICATION_GAS) {
            revert ProofVerificationGasIsTooLarge();
        }
        proofVerificationGas = _proofVerificationGas;
        emit UpdateProofVerificationGas(_proofVerificationGas);
    }

    /// @dev Update the Axiom query fee.
    /// @param  _axiomQueryFee the new Axiom query fee
    function _updateAxiomQueryFee(uint256 _axiomQueryFee) internal {
        if (_axiomQueryFee > MAX_AXIOM_QUERY_FEE) {
            revert AxiomQueryFeeIsTooLarge();
        }
        axiomQueryFee = _axiomQueryFee;
        emit UpdateAxiomQueryFee(_axiomQueryFee);
    }

    /// @dev Update the minimum allowed maxFeePerGas in a query.
    /// @param  _minMaxFeePerGas the new minimum allowed maxFeePerGas
    function _updateMinMaxFeePerGas(uint64 _minMaxFeePerGas) internal {
        if (_minMaxFeePerGas == 0) {
            revert MinMaxFeePerGasIsZero();
        }
        minMaxFeePerGas = _minMaxFeePerGas;
        emit UpdateMinMaxFeePerGas(_minMaxFeePerGas);
    }

    /// @notice Compute the query ID
    /// @param  queryHash The hash of the query.
    /// @param  callbackHash The hash of the callback, defined as `keccak(target || extraData)`
    /// @param  userSalt The user salt.
    /// @param  refundee The address to refund if the query is not fulfilled.
    /// @param  caller The address of the caller submitting the query.
    /// @return queryId The query ID.
    function _computeQueryId(
        bytes32 queryHash,
        bytes32 callbackHash,
        bytes32 userSalt,
        address refundee,
        address caller
    ) internal view returns (uint256 queryId) {
        queryId = uint256(
            keccak256(abi.encodePacked(uint64(block.chainid), caller, userSalt, queryHash, callbackHash, refundee))
        );
    }

    /// @notice Record on-chain query
    /// @param  queryId The unique ID identifying the query.
    /// @param  maxFeePerGas The maxFeePerGas parameter to use when calling the callback.
    /// @param  callbackGasLimit The gasLimit parameter to use when calling the callback.
    /// @param  overrideAxiomQueryFee If larger than `axiomQueryFee`, the value to be used for the query fee.
    function _sendQuery(uint256 queryId, uint64 maxFeePerGas, uint32 callbackGasLimit, uint256 overrideAxiomQueryFee)
        internal
    {
        if (queries[queryId].state != AXIOM_QUERY_STATE_INACTIVE) {
            revert QueryIsNotInactive();
        }

        if (maxFeePerGas < minMaxFeePerGas) {
            revert MaxFeePerGasIsTooLow();
        }

        uint256 _axiomQueryFee = axiomQueryFee;
        if (overrideAxiomQueryFee > _axiomQueryFee) {
            _axiomQueryFee = overrideAxiomQueryFee;
        }

        uint256 maxQueryPri = _getMaxQueryPri(maxFeePerGas, callbackGasLimit, _axiomQueryFee);
        if (msg.value != maxQueryPri) {
            if (msg.value > 0) {
                _recordDeposit(msg.sender, msg.value);
            }

            uint256 _callerBalance = balances[msg.sender];
            if (maxQueryPri > _callerBalance) {
                revert EscrowAmountExceedsBalance();
            }
            unchecked {
                // in this branch, we know that maxQueryPri <= balances[caller] (i.e. _callerBalance)
                balances[msg.sender] = _callerBalance - maxQueryPri;
            }
        } else {
            if (msg.value > MAX_DEPOSIT_SIZE) {
                revert DepositTooLarge();
            }
        }

        uint32 _queryDeadlineInterval = queryDeadlineInterval;
        queries[queryId] = AxiomQueryMetadata({
            state: AXIOM_QUERY_STATE_ACTIVE,
            deadlineBlockNumber: uint32(block.number) + _queryDeadlineInterval,
            callbackGasLimit: callbackGasLimit,
            payee: address(0),
            payment: maxQueryPri
        });
        emit QueryFeeInfoRecorded(
            queryId,
            msg.sender,
            uint32(block.number) + _queryDeadlineInterval,
            maxFeePerGas,
            callbackGasLimit,
            maxQueryPri
        );
    }

    /// @notice Verify a query result on-chain.
    /// @param  mmrWitness Witness data allowing verification of the proof against our cache of block hashes.
    /// @param  proof The ZK proof data.
    /// @param  target The callback address.
    /// @param  computeResultsHash The hash of the compute results.
    function _verifyResult(
        IAxiomV2HeaderVerifier.MmrWitness calldata mmrWitness,
        bytes calldata proof,
        address target,
        bytes32 computeResultsHash
    ) internal returns (AxiomProofData memory proofData) {
        //  The public instances are laid out in the proof calldata as follows:
        //    ** First 4 * 3 * 32 = 384 bytes are reserved for proof verification data used with the pairing precompile
        //    ** The next blocks of 11 groups of 32 bytes each are:
        //    ** `sourceChainId`                as a field element
        //    ** `computeResultsHash`           as 2 field elements, in hi-lo form
        //    ** `queryHash`                    as 2 field elements, in hi-lo form
        //    ** `querySchema`                  as 2 field elements, in hi-lo form
        //    ** `blockhashMmrKeccak` which is `keccak256(abi.encodePacked(mmr))` as 2 field elements in hi-lo form.
        //    ** `aggregateVkeyHash`            as a field element
        //    ** `payee`                        as a field element
        proofData.sourceChainId = uint64(uint256(bytes32(proof[384:384 + 32])));
        bytes32 proofComputeResultsHash = bytes32(
            (uint256(bytes32(proof[384 + 32:384 + 2 * 32])) << 128) | uint256(bytes32(proof[384 + 2 * 32:384 + 3 * 32]))
        );
        proofData.queryHash = bytes32(
            (uint256(bytes32(proof[384 + 3 * 32:384 + 4 * 32])) << 128)
                | uint256(bytes32(proof[384 + 4 * 32:384 + 5 * 32]))
        );
        proofData.querySchema = bytes32(
            (uint256(bytes32(proof[384 + 5 * 32:384 + 6 * 32])) << 128)
                | uint256(bytes32(proof[384 + 6 * 32:384 + 7 * 32]))
        );
        bytes32 blockhashMmrKeccak = bytes32(
            (uint256(bytes32(proof[384 + 7 * 32:384 + 8 * 32])) << 128)
                | uint256(bytes32(proof[384 + 8 * 32:384 + 9 * 32]))
        );
        bytes32 aggregateVkeyHash = bytes32(proof[384 + 9 * 32:384 + 10 * 32]);
        proofData.payee = address(uint160(uint256(bytes32(proof[384 + 10 * 32:384 + 11 * 32]))));

        address _axiomHeaderVerifierAddress = axiomHeaderVerifierAddress;

        // verify against on-chain data
        IAxiomV2HeaderVerifier(_axiomHeaderVerifierAddress).verifyQueryHeaders(blockhashMmrKeccak, mmrWitness);

        if (proofData.sourceChainId != IAxiomV2HeaderVerifier(_axiomHeaderVerifierAddress).getSourceChainId()) {
            revert SourceChainIdDoesNotMatch();
        }

        if (proofComputeResultsHash != computeResultsHash) {
            revert ComputeResultsHashDoesNotMatch();
        }

        if (
            !(
                hasRole(PROVER_ROLE, msg.sender) || hasRole(PROVER_ROLE, address(0))
                    || perQueryProvers[proofData.querySchema][target][msg.sender]
            )
        ) {
            revert ProverNotAuthorized();
        }

        if (
            !(
                aggregateVkeyHashes[aggregateVkeyHash]
                    || perQueryAggregateVkeyHashes[proofData.querySchema][target][aggregateVkeyHash]
            )
        ) {
            revert AggregateVkeyHashIsNotValid();
        }

        // verify the ZKP itself
        (bool success,) = verifierAddress.call(proof);
        if (!success) {
            revert ProofVerificationFailed();
        }
    }

    /// @notice Compute the price in ETH to escrow for each query.
    /// @param  maxFeePerGas The maxFeePerGas requested for the callback.
    /// @param  callbackGasLimit The gasLimit requested for the callback.
    /// @param  _axiomQueryFee The query fee for Axiom
    /// @return maxQueryPri The maximum amount of wei to escrow for the query.
    function _getMaxQueryPri(uint64 maxFeePerGas, uint32 callbackGasLimit, uint256 _axiomQueryFee)
        internal
        view
        returns (uint256 maxQueryPri)
    {
        maxQueryPri = maxFeePerGas * (callbackGasLimit + proofVerificationGas) + _axiomQueryFee;
    }

    /// @notice Record a deposit for fees to be paid by an account
    /// @param  payor The account receiving the deposit.
    /// @param  amount The amount of the deposit, in wei.
    function _recordDeposit(address payor, uint256 amount) internal {
        if (amount > MAX_DEPOSIT_SIZE) {
            revert DepositTooLarge();
        }

        unchecked {
            // balance cannot overflow
            balances[payor] += amount;
        }
        emit Deposit(payor, amount);
    }

    /// @notice Call a contract with no return value.
    /// @dev    Adapted from https://github.com/nomad-xyz/ExcessivelySafeCall/blob/main/src/ExcessivelySafeCall.sol
    ///         for the case that no return value is allowed.
    /// @param  _target The address of the contract to call.
    /// @param  _gas The gas to provide for the call.
    /// @param  _calldata The calldata to provide for the call.
    /// @return success True if the call succeeded, false otherwise.
    function _callWithNoReturn(address _target, uint256 _gas, bytes memory _calldata) internal returns (bool success) {
        assembly {
            success :=
                call(
                    _gas, // gas
                    _target, // recipient
                    0, // ether value
                    add(_calldata, 0x20), // inloc
                    mload(_calldata), // inlen
                    0, // outloc
                    0 // outlen
                )
        }
    }

    /// @inheritdoc AccessControlUpgradeable
    function supportsInterface(bytes4 interfaceId)
        public
        view
        virtual
        override(AccessControlUpgradeable)
        returns (bool)
    {
        return interfaceId == type(IAxiomV2Query).interfaceId || super.supportsInterface(interfaceId);
    }

    /// @inheritdoc UUPSUpgradeable
    function _authorizeUpgrade(address) internal override onlyRole(TIMELOCK_ROLE) { }

    /**
     * @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[40] private __gap;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (proxy/utils/UUPSUpgradeable.sol)

pragma solidity ^0.8.0;

import "../../interfaces/draft-IERC1822Upgradeable.sol";
import "../ERC1967/ERC1967UpgradeUpgradeable.sol";
import "./Initializable.sol";

/**
 * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
 * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
 *
 * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
 * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
 * `UUPSUpgradeable` with a custom implementation of upgrades.
 *
 * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
 *
 * _Available since v4.1._
 */
abstract contract UUPSUpgradeable is Initializable, IERC1822ProxiableUpgradeable, ERC1967UpgradeUpgradeable {
    function __UUPSUpgradeable_init() internal onlyInitializing {
    }

    function __UUPSUpgradeable_init_unchained() internal onlyInitializing {
    }
    /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
    address private immutable __self = address(this);

    /**
     * @dev Check that the execution is being performed through a delegatecall call and that the execution context is
     * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
     * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
     * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
     * fail.
     */
    modifier onlyProxy() {
        require(address(this) != __self, "Function must be called through delegatecall");
        require(_getImplementation() == __self, "Function must be called through active proxy");
        _;
    }

    /**
     * @dev Check that the execution is not being performed through a delegate call. This allows a function to be
     * callable on the implementing contract but not through proxies.
     */
    modifier notDelegated() {
        require(address(this) == __self, "UUPSUpgradeable: must not be called through delegatecall");
        _;
    }

    /**
     * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
     * implementation. It is used to validate the implementation's compatibility when performing an upgrade.
     *
     * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
     * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
     * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
     */
    function proxiableUUID() external view virtual override notDelegated returns (bytes32) {
        return _IMPLEMENTATION_SLOT;
    }

    /**
     * @dev Upgrade the implementation of the proxy to `newImplementation`.
     *
     * Calls {_authorizeUpgrade}.
     *
     * Emits an {Upgraded} event.
     */
    function upgradeTo(address newImplementation) external virtual onlyProxy {
        _authorizeUpgrade(newImplementation);
        _upgradeToAndCallUUPS(newImplementation, new bytes(0), false);
    }

    /**
     * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
     * encoded in `data`.
     *
     * Calls {_authorizeUpgrade}.
     *
     * Emits an {Upgraded} event.
     */
    function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual onlyProxy {
        _authorizeUpgrade(newImplementation);
        _upgradeToAndCallUUPS(newImplementation, data, true);
    }

    /**
     * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
     * {upgradeTo} and {upgradeToAndCall}.
     *
     * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
     *
     * ```solidity
     * function _authorizeUpgrade(address) internal override onlyOwner {}
     * ```
     */
    function _authorizeUpgrade(address newImplementation) internal virtual;

    /**
     * @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;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (access/AccessControl.sol)

pragma solidity ^0.8.0;

import "./IAccessControlUpgradeable.sol";
import "../utils/ContextUpgradeable.sol";
import "../utils/StringsUpgradeable.sol";
import "../utils/introspection/ERC165Upgradeable.sol";
import "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module that allows children to implement role-based access
 * control mechanisms. This is a lightweight version that doesn't allow enumerating role
 * members except through off-chain means by accessing the contract event logs. Some
 * applications may benefit from on-chain enumerability, for those cases see
 * {AccessControlEnumerable}.
 *
 * Roles are referred to by their `bytes32` identifier. These should be exposed
 * in the external API and be unique. The best way to achieve this is by
 * using `public constant` hash digests:
 *
 * ```
 * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
 * ```
 *
 * Roles can be used to represent a set of permissions. To restrict access to a
 * function call, use {hasRole}:
 *
 * ```
 * function foo() public {
 *     require(hasRole(MY_ROLE, msg.sender));
 *     ...
 * }
 * ```
 *
 * Roles can be granted and revoked dynamically via the {grantRole} and
 * {revokeRole} functions. Each role has an associated admin role, and only
 * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
 *
 * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
 * that only accounts with this role will be able to grant or revoke other
 * roles. More complex role relationships can be created by using
 * {_setRoleAdmin}.
 *
 * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
 * grant and revoke this role. Extra precautions should be taken to secure
 * accounts that have been granted it.
 */
abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControlUpgradeable, ERC165Upgradeable {
    function __AccessControl_init() internal onlyInitializing {
    }

    function __AccessControl_init_unchained() internal onlyInitializing {
    }
    struct RoleData {
        mapping(address => bool) members;
        bytes32 adminRole;
    }

    mapping(bytes32 => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

    /**
     * @dev Modifier that checks that an account has a specific role. Reverts
     * with a standardized message including the required role.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
     *
     * _Available since v4.1._
     */
    modifier onlyRole(bytes32 role) {
        _checkRole(role);
        _;
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControlUpgradeable).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
        return _roles[role].members[account];
    }

    /**
     * @dev Revert with a standard message if `_msgSender()` is missing `role`.
     * Overriding this function changes the behavior of the {onlyRole} modifier.
     *
     * Format of the revert message is described in {_checkRole}.
     *
     * _Available since v4.6._
     */
    function _checkRole(bytes32 role) internal view virtual {
        _checkRole(role, _msgSender());
    }

    /**
     * @dev Revert with a standard message if `account` is missing `role`.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
     */
    function _checkRole(bytes32 role, address account) internal view virtual {
        if (!hasRole(role, account)) {
            revert(
                string(
                    abi.encodePacked(
                        "AccessControl: account ",
                        StringsUpgradeable.toHexString(account),
                        " is missing role ",
                        StringsUpgradeable.toHexString(uint256(role), 32)
                    )
                )
            );
        }
    }

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
        return _roles[role].adminRole;
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleGranted} event.
     */
    function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
        _grantRole(role, account);
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleRevoked} event.
     */
    function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
        _revokeRole(role, account);
    }

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been revoked `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     *
     * May emit a {RoleRevoked} event.
     */
    function renounceRole(bytes32 role, address account) public virtual override {
        require(account == _msgSender(), "AccessControl: can only renounce roles for self");

        _revokeRole(role, account);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event. Note that unlike {grantRole}, this function doesn't perform any
     * checks on the calling account.
     *
     * May emit a {RoleGranted} event.
     *
     * [WARNING]
     * ====
     * This function should only be called from the constructor when setting
     * up the initial roles for the system.
     *
     * Using this function in any other way is effectively circumventing the admin
     * system imposed by {AccessControl}.
     * ====
     *
     * NOTE: This function is deprecated in favor of {_grantRole}.
     */
    function _setupRole(bytes32 role, address account) internal virtual {
        _grantRole(role, account);
    }

    /**
     * @dev Sets `adminRole` as ``role``'s admin role.
     *
     * Emits a {RoleAdminChanged} event.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        bytes32 previousAdminRole = getRoleAdmin(role);
        _roles[role].adminRole = adminRole;
        emit RoleAdminChanged(role, previousAdminRole, adminRole);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleGranted} event.
     */
    function _grantRole(bytes32 role, address account) internal virtual {
        if (!hasRole(role, account)) {
            _roles[role].members[account] = true;
            emit RoleGranted(role, account, _msgSender());
        }
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleRevoked} event.
     */
    function _revokeRole(bytes32 role, address account) internal virtual {
        if (hasRole(role, account)) {
            _roles[role].members[account] = false;
            emit RoleRevoked(role, account, _msgSender());
        }
    }

    /**
     * @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;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @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 functionCallWithValue(target, data, 0, "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");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, 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) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

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

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or 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 {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // 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);
        }
    }
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IAxiomV2HeaderVerifier {
    /**
     * @notice Stores witness data for checking MMRs
     * @param  snapshotPmmrSize The `pmmrSize` as in `IAxiomV2State`.
     * @param  proofMmrPeaks Peaks of the MMR, formatted so that `proofMmrPeaks[i]` is a Merkle
     *         root of `2 ** i` claimed block hashes.
     * @param  mmrComplementOrPeaks This has two different semantic meanings depending on the
     *         value of `proofPmmrSize = number of blocks committed to by proofMmrPeaks`.
     *         If `proofPmmrSize <= snapshotPmmrSize`:
     *           -- `mmrComplementOrPeaks[:10]` form a complementary MMR to `proofMmrPeaks[:10]`
     *              formatted so that `mmrComplementOrPeaks[idx]` is a Merkle root of `2 ** idx` hashes
     *              which together with `witnessMmrPeaks` forms a padded leaf.
     *           -- `mmrComplementOrPeaks[10]` is either `bytes32(0x0)` or a Merkle root of a padded leaf.
     *              -- It is expected to be a Merkle root of a padded leaf exactly when
     *                    snapshotPmmrSize % BLOCK_BATCH_SIZE != 0
     *           -- The remaining elements are a list of Merkle roots of 1024 block hashes, to be
     *              appended in increasing index order.
     *         If `proofPmmrSize > snapshotPmmrSize`:
     *           -- This is the MMR peaks committed to in the PMMR at `snapshotPmmrSize`,
     *              formatted so that `mmrComplementOrPeaks[idx]` is a Merkle root of `2 ** idx`
     *              block hashes.
     */
    struct MmrWitness {
        uint32 snapshotPmmrSize;
        bytes32[] proofMmrPeaks;
        bytes32[] mmrComplementOrPeaks;
    }

    /// @notice Error returned if the AxiomV2Core address is 0.
    error AxiomCoreAddressIsZero();

    /// @notice Error returned when the claimed blockhashMmr is not consistent with the source of truth
    error BlockhashMmrKeccakDoesNotMatchProof();

    /// @notice Error returned when last block in the claimed MMR of the proof is not in the recent 256
    ///         block hash window.
    error MmrEndBlockNotRecent();

    /// @notice Error returned when last block in the claimed MMR of the proof is not in the recent 256
    ///         block hash window.
    error BlockHashWitnessNotRecent();

    /// @notice Error returned when the claimed MMR of the proof is not consistent with the source of truth
    error ClaimedMmrDoesNotMatchRecent();

    /// @notice Error returned when the claimed MMR of the proof cannot be verified against a more recent
    ///         blockhashPmmr.
    error NoMoreRecentBlockhashPmmr();

    /// @notice Error returned if the proofMmrKeccak does not match witness.
    error ProofMmrKeccakDoesNotMatch();

    /// @notice Verify the claimed `proofMmrKeccak` is validly read from the history
    ///         of the source chain using witness data from `mmrWitness`
    /// @param  proofMmrKeccak The Keccak hash of the claimed MMR of historic block hashes
    ///         formatted so that hash `idx` is the Merkle root of `2 ** idx` block hashes
    /// @param  mmrWitness Witness data for verification
    function verifyQueryHeaders(bytes32 proofMmrKeccak, MmrWitness calldata mmrWitness) external;

    /// @notice Return the `chainId` of the source chain
    /// @return chainId The `chainId`
    function getSourceChainId() external view returns (uint64);
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import { IAxiomV2HeaderVerifier } from "./IAxiomV2HeaderVerifier.sol";

/// @dev States of an query.
///         We call a query on-chain if it is requested on-chain with `sendQuery` or `sendQueryWithIpfs`.
///         We also allow a query to be fulfilled on-chain without an on-chain request (which we call off-chain),
///         but to make sure the off-chain queries don't interfere with on-chain queries, we require that they are
///         in state `Inactive`.
/// @dev  Inactive The query has not been made or was refunded.
/// @dev  Active The query has been requested, but not fulfilled.
/// @dev  Fulfilled The query was successfully fulfilled.
/// @dev  Paid The query was successfully fulfilled and the payee has claimed the escrow amount.
uint8 constant AXIOM_QUERY_STATE_INACTIVE = 0;
uint8 constant AXIOM_QUERY_STATE_ACTIVE = 1;
uint8 constant AXIOM_QUERY_STATE_FULFILLED = 2;
uint8 constant AXIOM_QUERY_STATE_PAID = 3;

interface IAxiomV2Query {
    /// @notice Stores metadata about a query
    /// @param  state The state of the query.
    /// @param  deadlineBlockNumber The deadline (in block number) after which a refund may be granted.
    /// @param  callbackGasLimit The gasLimit the payee wishes the callback to be called with.
    /// @param  payee The address of the account that will receive payment.
    /// @param  payment The amount of the payment, in wei.
    struct AxiomQueryMetadata {
        uint8 state;
        uint32 deadlineBlockNumber;
        uint32 callbackGasLimit;
        address payee;
        uint256 payment;
    }

    /// @notice Stores data for initialization of AxiomV2Query
    /// @param  axiomHeaderVerifierAddress The address of the IAxiomV2HeaderVerifier.
    /// @param  verifierAddress The address of the ZK verifier for queries.
    /// @param  proverAddresses A list of allowed provers for all queries.
    /// @param  aggregateVkeyHashes A list of allowed aggregateVkeyHashes for query verification
    /// @param  queryDeadlineInterval The number of blocks after which a query may be refunded.
    /// @param  proofVerificationGas The amount of gas allotted for ZK proof verification.
    /// @param  axiomQueryFee The fee, in gwei, paid to Axiom for query fulfillment.
    /// @param  minMaxFeePerGas The minimum `maxFeePerGas` allowed in a query.
    /// @param  maxQueryDeadlineInterval The maximum `queryDeadlineInterval` allowed.
    /// @param  timelock The address of the timelock contract.
    /// @param  guardian The address of the guardian contract.
    /// @param  unfreeze The address of the unfreeze contract.
    struct AxiomV2QueryInit {
        address axiomHeaderVerifierAddress;
        address verifierAddress;
        address[] proverAddresses;
        bytes32[] aggregateVkeyHashes;
        uint32 queryDeadlineInterval;
        uint32 proofVerificationGas;
        uint256 axiomQueryFee;
        uint64 minMaxFeePerGas;
        uint32 maxQueryDeadlineInterval;
        address timelock;
        address guardian;
        address unfreeze;
    }

    /// @notice Stores witness data associated to a queryId.
    /// @param  caller The address of the account that initiated the query.
    /// @param  userSalt The salt used to generate the queryId.
    /// @param  queryHash Hash of the query data.
    /// @param  callbackHash Hash of the callback data.
    /// @param  refundee The address to send any refunds to.
    struct AxiomV2QueryWitness {
        address caller;
        bytes32 userSalt;
        bytes32 queryHash;
        bytes32 callbackHash;
        address refundee;
    }

    /// @notice Stores public instances of the query fulfillment proof
    /// @param  sourceChainId The ID of the chain the query reads from.
    /// @param  queryHash The unique hash identifier of the query.
    /// @param  querySchema The schema of the query, defined as `keccak(k . resultLen . vkeyLen . vkey)`
    /// @param  payee The address of the account that will receive payment.
    struct AxiomProofData {
        uint64 sourceChainId;
        bytes32 queryHash;
        bytes32 querySchema;
        address payee;
    }

    /// @notice Stores data associated to the compute query circuit.
    /// @param  k The degree of the circuit.
    /// @param  resultLen The number of meaningful public outputs of the circuit.  If no compute query
    ///         is defined, this is the number of data subqueries which should be passed to a callback.
    /// @param  vkey The verification key of the circuit.
    /// @param  computeProof The proof data of the circuit.
    struct AxiomV2ComputeQuery {
        uint8 k;
        uint16 resultLen;
        bytes32[] vkey;
        bytes computeProof;
    }

    /// @notice Stores data associated to the callback to be called after query fulfillment.
    ///         The callback will correspond to the function signature of `axiomV2Callback` or
    ///         `axiomV2OffchainCallback` in `IAxiomV2Client`.  It is not payable, and no ETH will
    ///         be forwarded.
    /// @param  target The address of the contract to call with the query results.
    /// @param  extraData Extra data to be passed to the callback function.
    struct AxiomV2Callback {
        address target;
        bytes extraData;
    }

    /// @notice Stores data associated to the fees to be paid for the query.
    /// @param  maxFeePerGas The maximum fee per gas the payee wishes the callback to be called with.
    /// @param  callbackGasLimit The gasLimit the payee wishes the callback to be called with.
    /// @param  overrideAxiomQueryFee If larger than `axiomQueryFee`, the value to be used for the query fee.
    struct AxiomV2FeeData {
        uint64 maxFeePerGas;
        uint32 callbackGasLimit;
        uint256 overrideAxiomQueryFee;
    }

    /// @dev Error returned if the AxiomV2HeaderVerifier address is 0.
    error AxiomHeaderVerifierAddressIsZero();

    /// @dev Error returned if the ZK proof verifier address is 0.
    error VerifierAddressIsZero();

    /// @dev Error returned if the AxiomV2Prover address is 0.
    error AxiomProverAddressIsZero();

    /// @dev Error returned if the timelock address is 0.
    error TimelockAddressIsZero();

    /// @dev Error returned if the guardian address is 0.
    error GuardianAddressIsZero();

    /// @dev Error returned if the unfreeze address is 0.
    error UnfreezeAddressIsZero();

    /// @dev Error returned if the prover address is 0.
    error ProverAddressIsZero();

    /// @dev Error returned if an unauthorized prover attempts to fulfill a query.
    error ProverNotAuthorized();

    /// @dev Error returned if the payor address deposited to is 0
    error PayorAddressIsZero();

    /// @dev Error returned if the payee address withdrawn to is 0
    error PayeeAddressIsZero();

    /// @dev Error returned if deposit is 0
    error DepositAmountIsZero();

    /// @dev Error returned if withdrawal is 0
    error WithdrawalAmountIsZero();

    /// @dev Error returned if minMaxFeePerGas is 0
    error MinMaxFeePerGasIsZero();

    /// @dev Error returned if the query deadline interval is too large
    error QueryDeadlineIntervalIsTooLarge();

    /// @dev Error returned if the proofVerificationGas exceeds a conservative bound
    error ProofVerificationGasIsTooLarge();

    /// @dev Error returned if the axiomQueryFee exceeds a conservative bound
    error AxiomQueryFeeIsTooLarge();

    /// @dev Error returned if a deposit exceeds `MAX_DEPOSIT_SIZE`.
    error DepositTooLarge();

    /// @dev Error returned if an on-chain query is not in state `Active` upon fulfillment.
    error CannotFulfillIfNotActive();

    /// @dev Error returned if an off-chain query is not in state `Inactive` upon fulfillment.
    error CannotFulfillFromOffchainIfNotInactive();

    /// @dev Error returned if an on-chain query is attempted to be refunded by an address that is not the `refundee`.
    error CannotRefundIfNotRefundee();

    /// @dev Error returned if an on-chain query is not in state `Active` upon refund.
    error CannotRefundIfNotActive();

    /// @dev Error returned if a refund is requested for an on-chain query before `queryDeadlineInterval`.
    error CannotRefundBeforeDeadline();

    /// @dev Error returned if the `queryHash` does not match the value in the ZK proof.
    error QueryHashDoesNotMatchProof();

    /// @dev Error returned if ZK proof verification failed.
    error ProofVerificationFailed();

    /// @dev Error returned the compute results hash does not match.
    error ComputeResultsHashDoesNotMatch();

    /// @dev Error returned if the `sourceChainId` does not match.
    error SourceChainIdDoesNotMatch();

    /// @dev Error returned if the `aggregateVkeyHash` in the proof is not allowed.
    error AggregateVkeyHashIsNotValid();

    /// @dev Error returned if the new `maxQueryPri` is not larger.
    error NewMaxQueryPriMustBeLargerThanPrevious();

    /// @dev Error returned if the query requestor does not have sufficient funds.
    error InsufficientFunds();

    /// @dev Error returned if there is insufficient gas for the requested callback gas limit
    ///      when fulfilling an on-chain query.
    error InsufficientGasForCallback();

    /// @dev Error returned if `callbackHash` does not match the `queryWitness`
    error CallbackHashDoesNotMatchQueryWitness();

    /// @dev Error returned if a requested escrow amount exceeds a user balance.
    error EscrowAmountExceedsBalance();

    /// @dev Error returned if a gas increase is requested on a query which is not active.
    error CanOnlyIncreaseGasOnActiveQuery();

    /// @dev Error returned if a query is not in state `Fulfilled`.
    error QueryIsNotFulfilled();

    /// @dev Error returned if a query is not in state `Inactive`.
    error QueryIsNotInactive();

    /// @dev Error returned if the requested unescrow amount exceeds the escrow.
    error UnescrowAmountExceedsEscrowedAmount();

    /// @dev Error returned if the unescrow request is not from the payee.
    error OnlyPayeeCanUnescrow();

    /// @dev Error returned if caller of an offchain fulfillment is not the payee.
    error OnlyPayeeCanFulfillOffchainQuery();

    /// @dev Error returned if the withdrawal amount exceeds a user's balance.
    error WithdrawalAmountExceedsFreeBalance();

    /// @dev Error returned if the `maxFeePerGas` is too low.
    error MaxFeePerGasIsTooLow();

    /// @notice Emitted when the `IAxiomV2HeaderVerifier` address is updated.
    /// @param  newAddress The updated address.
    event UpdateAxiomHeaderVerifierAddress(address newAddress);

    /// @notice Emitted when the query verifier address is updated.
    /// @param  newAddress The updated address.
    event UpdateVerifierAddress(address newAddress);

    /// @notice Emitted when the prover address is updated.
    /// @param  newAddress The updated address.
    event UpdateAxiomProverAddress(address newAddress);

    /// @notice Emitted when an aggregateVkeyHash is added for a given query schema and callback
    /// @param  querySchema The query schema
    /// @param  target The callback address
    /// @param  aggregateVkeyHash The aggregateVkeyHash
    event AddPerQueryAggregateVkeyHash(bytes32 indexed querySchema, address target, bytes32 aggregateVkeyHash);

    /// @notice Emitted when an aggregateVkeyHash is removed for a given query schema and callback
    /// @param  querySchema The query schema
    /// @param  target The callback address
    /// @param  aggregateVkeyHash The aggregateVkeyHash
    event RemovePerQueryAggregateVkeyHash(bytes32 indexed querySchema, address target, bytes32 aggregateVkeyHash);

    /// @notice Emitted when a new aggregateVkeyHash is added which applies to all queries
    /// @param  aggregateVkeyHash The `aggregateVkeyHash` which was added.
    event AddAggregateVkeyHash(bytes32 indexed aggregateVkeyHash);

    /// @notice Emitted when an aggregateVkeyHash is removed which applies to all queries
    /// @param  aggregateVkeyHash The `aggregateVkeyHash` which was removed.
    event RemoveAggregateVkeyHash(bytes32 indexed aggregateVkeyHash);

    /// @notice Emitted when the query deadline interval is updated
    /// @param  newQueryDeadlineInterval The updated query deadline interval.
    event UpdateQueryDeadlineInterval(uint32 newQueryDeadlineInterval);

    /// @notice Emitted when the proof gas is updated
    /// @param  newProofVerificationGas The updated proof gas.
    event UpdateProofVerificationGas(uint32 newProofVerificationGas);

    /// @notice Emitted when the query fee is updated
    /// @param  newAxiomQueryFee The updated query fee.
    event UpdateAxiomQueryFee(uint256 newAxiomQueryFee);

    /// @notice Emitted when the mininum value of maxFeePerGas is updated
    /// @param  newMinMaxFeePerGas The updated maxFeePerGas.
    event UpdateMinMaxFeePerGas(uint64 newMinMaxFeePerGas);

    /// @notice Emitted when a query is initiated on-chain.
    /// @param  caller The address of the account that initiated the query.
    /// @param  queryHash The unique hash identifying the query.
    /// @param  queryId The unique ID identifying the query.
    /// @param  userSalt The salt used to generate the query hash.
    /// @param  refundee The address to send any refunds to.
    /// @param  target The address of the contract to call with the query results.
    /// @param  extraData Extra data to be passed to the callback function.
    event QueryInitiatedOnchain(
        address indexed caller,
        bytes32 indexed queryHash,
        uint256 indexed queryId,
        bytes32 userSalt,
        address refundee,
        address target,
        bytes extraData
    );

    /// @notice Emitted when a query is initiated with data availability on IPFS.
    /// @param  caller The address of the account that initiated the query.
    /// @param  queryHash The unique hash identifying the query.
    /// @param  queryId The unique ID identifying the query.
    /// @param  userSalt The salt used to generate the query hash.
    /// @param  ipfsHash The IPFS hash with the query.
    /// @param  refundee The address to send any refunds to.
    /// @param  target The address of the contract to call with the query results.
    /// @param  extraData Extra data to be passed to the callback function.
    event QueryInitiatedWithIpfsData(
        address indexed caller,
        bytes32 indexed queryHash,
        uint256 indexed queryId,
        bytes32 userSalt,
        bytes32 ipfsHash,
        address refundee,
        address target,
        bytes extraData
    );

    /// @notice Emitted when a query is initiated.
    /// @param  queryId The unique ID identifying the query.
    /// @param  payor The account paying for the query.
    /// @param  deadlineBlockNumber The deadline (in block number) after which a refund may be granted.
    /// @param  maxFeePerGas The maximum fee per gas the payee wishes the callback to be called with.
    /// @param  callbackGasLimit The gasLimit the payee wishes the callback to be called with.
    /// @param  amount The amount of the payment, in wei.
    event QueryFeeInfoRecorded(
        uint256 indexed queryId,
        address indexed payor,
        uint32 deadlineBlockNumber,
        uint64 maxFeePerGas,
        uint32 callbackGasLimit,
        uint256 amount
    );

    /// @notice Emitted when the gas allowance for a query is increased.
    /// @param  queryId The unique ID of the query.
    /// @param  maxFeePerGas The maximum fee per gas the payee wishes the callback to be called with.
    /// @param  callbackGasLimit The gasLimit the payee wishes the callback to be called with.
    /// @param  overrideAxiomQueryFee If larger than `axiomQueryFee`, the value to be used for the query fee.
    event QueryGasIncreased(
        uint256 indexed queryId, uint64 maxFeePerGas, uint32 callbackGasLimit, uint256 overrideAxiomQueryFee
    );

    /// @notice Emitted when a query requested on-chain is fulfilled.
    /// @param  queryId The unique ID identifying the query.
    /// @param  payee The address of the account that will receive payment.
    /// @param  callbackSucceeded Whether the callback succeeded.  This will be `false` if no callback was requested.
    event QueryFulfilled(uint256 indexed queryId, address payee, bool callbackSucceeded);

    /// @notice Emitted when a query requested off-chain is fulfilled.
    /// @param  queryId The unique ID identifying the query.
    /// @param  callbackSucceeded Whether the callback succeeded.  This will be `false` if no callback was requested.
    event OffchainQueryFulfilled(uint256 indexed queryId, bool callbackSucceeded);

    /// @notice Emitted when a query is refunded.
    /// @param  queryId The unique ID identifying the query.
    /// @param  refundee The address the refund is sent to.
    event QueryRefunded(uint256 indexed queryId, address indexed refundee);

    /// @notice Emitted when a deposit is made for fees to be paid by an account
    /// @param  payor The account receiving the deposit.
    /// @param  amount The amount of the deposit, in wei.
    event Deposit(address indexed payor, uint256 amount);

    /// @notice Emitted when payment is claimed by the payee
    /// @param  payor The account paying for the query.
    /// @param  queryId The unique ID identifying the query.
    /// @param  payee The account receiving payment.
    /// @param  refundee The account receiving a partial refund.
    /// @param  amountUsed The amount of the escrow used, in wei.
    event Unescrow(
        address indexed payor, uint256 indexed queryId, address indexed payee, address refundee, uint256 amountUsed
    );

    /// @notice Emitted when a withdrawal is made of unused funds.
    /// @param  payor The account to withdraw from.
    /// @param  amount The amount of the withdrawal, in wei.
    /// @param  payee The address receiving the withdrawal.
    event Withdraw(address indexed payor, uint256 amount, address payee);

    /// @notice Emitted when a prover is added for a given query schema and callback
    /// @param  querySchema The query schema
    /// @param  target The callback address
    /// @param  prover The prover address
    event AddPerQueryProver(bytes32 indexed querySchema, address target, address prover);

    /// @notice Emitted when a prover is removed for a given query schema and callback
    /// @param  querySchema The query schema
    /// @param  target The callback address
    /// @param  prover The prover address
    event RemovePerQueryProver(bytes32 indexed querySchema, address target, address prover);

    /// @notice Send a query to Axiom. See `AxiomV2ComputeQuery` for documentation on the compute query and
    ///         `AxiomV2Callback` for documentation on the callback format.
    /// @param  sourceChainId The ID of the chain the query reads from.
    /// @param  dataQueryHash The hash of the data query.
    /// @param  computeQuery The data associated to the compute query circuit.
    /// @param  callback The data associated to the callback to be called after query fulfillment.
    /// @param  feeData The data associated to the fees to be paid for the query.
    /// @param  userSalt The salt used to generate the queryId.
    /// @param  refundee The address to send any refunds to.
    /// @param  dataQuery The raw data query.
    /// @return queryId The unique ID identifying the query.
    function sendQuery(
        uint64 sourceChainId,
        bytes32 dataQueryHash,
        AxiomV2ComputeQuery calldata computeQuery,
        AxiomV2Callback calldata callback,
        AxiomV2FeeData calldata feeData,
        bytes32 userSalt,
        address refundee,
        bytes calldata dataQuery
    ) external payable returns (uint256 queryId);

    /// @notice Send a query to Axiom with data availability on IPFS. See `AxiomV2ComputeQuery` for documentation
    ///         on the compute query and `AxiomV2Callback` for documentation on the callback format.
    /// @param  queryHash The unique hash identifying the query.
    /// @param  ipfsHash The IPFS hash with the query.
    /// @param  callback The data associated to the callback to be called after query fulfillment.
    /// @param  feeData The data associated to the fees to be paid for the query.
    /// @param  userSalt The salt used to generate the queryId.
    /// @param  refundee The address to send any refunds to.
    /// @return queryId The unique ID identifying the query.
    function sendQueryWithIpfsData(
        bytes32 queryHash,
        bytes32 ipfsHash,
        AxiomV2Callback calldata callback,
        AxiomV2FeeData calldata feeData,
        bytes32 userSalt,
        address refundee
    ) external payable returns (uint256 queryId);

    /// @notice Increase the fees allocated for a query while paying additional fees. Anyone can call this.
    ///         Excess funds are allocated to the account of the sender.
    /// @param  queryId The unique ID identifying the query.
    /// @param  newMaxFeePerGas The new maximum fee per gas the payee wishes the callback to be called with.
    /// @param  newCallbackGasLimit The new gasLimit the payee wishes the callback to be called with.
    /// @param  overrideAxiomQueryFee If larger than `axiomQueryFee`, the value to be used for the query fee.
    function increaseQueryGas(
        uint256 queryId,
        uint64 newMaxFeePerGas,
        uint32 newCallbackGasLimit,
        uint256 overrideAxiomQueryFee
    ) external payable;

    /// @notice Fulfill an Axiom query made on-chain.
    /// @param  mmrWitness Witness data allowing verification of the proof against the MMR of block
    ///         hashes in AxiomV2Core.
    /// @param  computeResults The query results to be passed to the callback.
    /// @param  proof The ZK proof data.
    /// @param  callback Callback to be called after.
    /// @param  queryWitness Witness data identifying the query.
    function fulfillQuery(
        IAxiomV2HeaderVerifier.MmrWitness calldata mmrWitness,
        bytes32[] calldata computeResults,
        bytes calldata proof,
        AxiomV2Callback calldata callback,
        AxiomV2QueryWitness calldata queryWitness
    ) external;

    /// @notice Fulfill an Axiom query made off-chain. See `AxiomV2Callback` for documentation on the callback format.
    /// @param  mmrWitness Witness data allowing verification of the proof against the MMR of block
    ///         hashes in AxiomV2Core.
    /// @param  computeResults The query results to be passed to the callback.
    /// @param  proof The ZK proof data.
    /// @param  callback The callback to be called with the query results.
    /// @param  userSalt The salt used to generate the queryId
    function fulfillOffchainQuery(
        IAxiomV2HeaderVerifier.MmrWitness calldata mmrWitness,
        bytes32[] calldata computeResults,
        bytes calldata proof,
        AxiomV2Callback calldata callback,
        bytes32 userSalt
    ) external;

    /// @notice Refund a query.
    /// @param  queryWitness Witness data identifying the query.
    function refundQuery(AxiomV2QueryWitness calldata queryWitness) external;

    /// @notice Deposit funds to be used for query fees
    /// @param  payor The account receiving the deposit.
    function deposit(address payor) external payable;

    /// @notice Claim payment for a query
    /// @param  queryWitness Witness data identifying the query.
    /// @param  amountUsed The amount of the escrow used, in wei.
    function unescrow(AxiomV2QueryWitness calldata queryWitness, uint256 amountUsed) external;

    /// @notice Withdraw unused funds.
    /// @param  amount The amount of the withdrawal, in wei.
    /// @param  payee The address receiving the withdrawal.
    function withdraw(uint256 amount, address payable payee) external;
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IAxiomV2Client {
    /// @notice Emitted when a callback is made from AxiomV2Query via an on-chain query.
    /// @param  sourceChainId The ID of the chain the query reads from.
    /// @param  caller The address of the account that initiated the query.
    /// @param  querySchema The schema of the query, defined as `keccak(k . resultLen . vkeyLen . vkey)`
    /// @param  queryId The unique ID identifying the query.
    event AxiomV2Call(
        uint64 indexed sourceChainId, address caller, bytes32 indexed querySchema, uint256 indexed queryId
    );

    /// @notice Emitted when a callback is made from AxiomV2Query via an off-chain query.
    /// @param  sourceChainId The ID of the chain the query reads from.
    /// @param  caller The address of the account that initiated the query fulfillment.
    /// @param  querySchema The schema of the query, defined as `keccak(k . resultLen . vkeyLen . vkey)`
    /// @param  queryId The unique ID identifying the query.
    event AxiomV2OffchainCall(
        uint64 indexed sourceChainId, address caller, bytes32 indexed querySchema, uint256 indexed queryId
    );

    /// @notice Return the address of the AxiomV2Query contract.
    /// @return The address of the AxiomV2Query contract.
    function axiomV2QueryAddress() external view returns (address);

    /// @notice Callback which is intended to be called upon on-chain query fulfillment by AxiomV2Query
    /// @param  sourceChainId The ID of the chain the query reads from.
    /// @param  caller The address of the account that initiated the query.
    /// @param  querySchema The schema of the query, defined as `keccak(k . resultLen . vkeyLen . vkey)`
    /// @param  queryId The unique ID identifying the query.
    /// @param  axiomResults The results of the query.
    /// @param  extraData Additional data passed to the callback.
    function axiomV2Callback(
        uint64 sourceChainId,
        address caller,
        bytes32 querySchema,
        uint256 queryId,
        bytes32[] calldata axiomResults,
        bytes calldata extraData
    ) external;

    /// @notice Callback which is intended to be called upon off-chain query fulfillment by AxiomV2Query
    /// @param  sourceChainId The ID of the chain the query reads from.
    /// @param  caller The address of the account that initiated the query fulfillment.
    /// @param  querySchema The schema of the query, defined as `keccak(k . resultLen . vkeyLen . vkey)`
    /// @param  queryId The unique ID identifying the query.
    /// @param  axiomResults The results of the query.
    /// @param  extraData Additional data passed to the callback.
    function axiomV2OffchainCallback(
        uint64 sourceChainId,
        address caller,
        bytes32 querySchema,
        uint256 queryId,
        bytes32[] calldata axiomResults,
        bytes calldata extraData
    ) external;

    /// @dev Error returned if initialized with `axiomV2QueryAddress` set to the zero address.
    error AxiomV2QueryAddressIsZero();

    /// @dev Error returned if the caller is not the AxiomV2Query contract.
    error CallerMustBeAxiomV2Query();
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

import { AccessControlUpgradeable } from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

/// @title  AxiomAccess
/// @notice Abstract contract controlling permissions of Axiom contracts
/// @dev    For use in a UUPS upgradeable contract.
abstract contract AxiomAccess is Initializable, AccessControlUpgradeable {
    bool public frozen;

    /// @notice Storage slot for the address with the permission of a 'timelock'.
    bytes32 public constant TIMELOCK_ROLE = keccak256("TIMELOCK_ROLE");

    /// @notice Storage slot for the addresses with the permission of a 'guardian'.
    bytes32 public constant GUARDIAN_ROLE = keccak256("GUARDIAN_ROLE");

    /// @notice Storage slot for the addresses with the permission of a 'unfreezer'.
    bytes32 public constant UNFREEZE_ROLE = keccak256("UNFREEZE_ROLE");

    /// @notice Storage slot for the addresses with the permission of a 'prover'.
    bytes32 public constant PROVER_ROLE = keccak256("PROVER_ROLE");

    /// @notice Storage slot for the addresses with the permission of different Axiom versions.
    bytes32 public constant AXIOM_ROLE = keccak256("AXIOM_ROLE");

    /// @notice Emitted when the `freezeAll` is called
    event FreezeAll();

    /// @notice Emitted when the `unfreezeAll` is called
    event UnfreezeAll();

    /// @notice Error when trying to call contract while it is frozen
    error ContractIsFrozen();

    /// @notice Error when trying to call contract from address without 'prover' role
    error NotProverRole();

    /// @notice Error when trying to call contract from address without Axiom role
    error NotAxiomRole();

    /**
     * @dev Modifier to make a function callable only by the 'prover' role.
     * As an initial safety mechanism, the 'update_' functions are only callable by the 'prover' role.
     * Granting the prover role to `address(0)` will enable this role for everyone.
     */
    modifier onlyProver() {
        _checkProver();
        _;
    }

    /// @notice Checks that the contract is not frozen.
    modifier onlyNotFrozen() {
        _checkNotFrozen();
        _;
    }

    /// @dev Factor out prover check to reduce contract size.
    function _checkProver() internal view {
        if (!(hasRole(PROVER_ROLE, address(0)) || hasRole(PROVER_ROLE, _msgSender()))) {
            revert NotProverRole();
        }
    }

    /// @dev Factor out freeze check to reduce contract size.
    function _checkNotFrozen() internal view {
        if (frozen) {
            revert ContractIsFrozen();
        }
    }

    /// @notice Initializes the contract in the unfrozen state
    function __AxiomAccess_init() internal onlyInitializing {
        __AxiomAccess_init_unchained();
    }

    /// @notice Initializes the contract in the unfrozen state
    function __AxiomAccess_init_unchained() internal onlyInitializing {
        frozen = false;
    }

    /// @notice Set the contract state to frozen, which will disable a set of security-sensitive functions.
    ///         Intended only for use in reaction to an unforeseen vulnerability in ZK circuits or smart contracts.
    function freezeAll() external onlyRole(GUARDIAN_ROLE) {
        frozen = true;
        emit FreezeAll();
    }

    /// @notice Set the contract state to unfrozen, which re-enables a set of security-sensitive functions.
    ///         Intended for use after any vulnerability or potential vulnerability leading to a freeze is fixed.
    function unfreezeAll() external onlyRole(UNFREEZE_ROLE) {
        frozen = false;
        emit UnfreezeAll();
    }

    /**
     * @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[40] private __gap;
}

File 9 of 22 : AxiomV2Configuration.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Constants and free functions to be inlined into by AxiomV2Core and AxiomV2Query

/*
 * Constants for AxiomV2Core
 */

// AxiomV2Core caches blockhashes in batches, stored as Merkle roots of binary Merkle trees
uint32 constant BLOCK_BATCH_SIZE = 1024;
uint32 constant BLOCK_BATCH_DEPTH = 10;

// constants for batch import of historical block hashes
// historical uploads a bigger batch of block hashes, stored as Merkle roots of binary Merkle trees
uint32 constant HISTORICAL_BLOCK_BATCH_SIZE = 131_072; // 2 ** 17
uint32 constant HISTORICAL_BLOCK_BATCH_DEPTH = 17;
// we will consider the historical Merkle tree of blocks as a Merkle tree of the block batch roots
uint32 constant HISTORICAL_NUM_ROOTS = 128; // HISTORICAL_BATCH_SIZE / BLOCK_BATCH_SIZE

// The first 4 * 3 * 32 bytes of proof calldata are reserved for two BN254 G1 points for a pairing check
// It will then be followed by (7 + BLOCK_BATCH_DEPTH * 2) * 32 bytes of public inputs/outputs
uint32 constant PUBLIC_BYTES_START_IDX = 384; // 4 * 3 * 32
uint32 constant AUX_PEAKS_START_IDX = 608; // PUBLIC_BYTES_START_IDX + 7 * 32

/// @notice Read public instances from the ZK proof
/// @param  proofData the entire ZK proof
/// @return prevHash the hash of the previous block
/// @return endHash the hash of the last block in the batch
/// @return startBlockNumber the block number of the first block in the batch
/// @return endBlockNumber the block number of the last block in the batch
/// @return root the Merkle root of the 0-padded batch of blocks
/// @dev proofData stores bytes32 and uint256 values in hi-lo format as two uint128 values because the BN254 scalar field is 254 bits
/// @dev The first 12 * 32 bytes of proofData are reserved for ZK proof verification data
// Extract public instances from proof
// The public instances are laid out in the proof calldata as follows:
// First 4 * 3 * 32 = 384 bytes are reserved for proof verification data used with the pairing precompile
// 384..384 + 32 * 2: prevHash (32 bytes) as two uint128 cast to uint256, because zk proof uses 254 bit field and cannot fit uint256 into a single element
// 384 + 32 * 2..384 + 32 * 4: endHash (32 bytes) as two uint128 cast to uint256
// 384 + 32 * 4..384 + 32 * 5: startBlockNumber (uint32: 4 bytes) and endBlockNumber (uint32: 4 bytes) are concatenated as `startBlockNumber . endBlockNumber` (8 bytes) and then cast to uint256
// 384 + 32 * 5..384 + 32 * 7: root (32 bytes) as two uint128 cast to uint256, this is the highest peak of the MMR if endBlockNumber - startBlockNumber == 1023, otherwise 0
function getBoundaryBlockData(bytes calldata proofData)
    pure
    returns (bytes32 prevHash, bytes32 endHash, uint32 startBlockNumber, uint32 endBlockNumber, bytes32 root)
{
    prevHash =
        bytes32(uint256(bytes32(proofData[PUBLIC_BYTES_START_IDX:416])) << 128 | uint256(bytes32(proofData[416:448])));
    endHash = bytes32(uint256(bytes32(proofData[448:480])) << 128 | uint256(bytes32(proofData[480:512])));
    startBlockNumber = uint32(bytes4(proofData[536:540]));
    endBlockNumber = uint32(bytes4(proofData[540:544]));
    root = bytes32(uint256(bytes32(proofData[544:576])) << 128 | uint256(bytes32(proofData[576:AUX_PEAKS_START_IDX])));
}

// We have a Merkle mountain range of max depth BLOCK_BATCH_DEPTH (so length BLOCK_BATCH_DEPTH + 1 total) ordered in **decreasing** order of peak size, so:
// `root` from `getBoundaryBlockData` is the peak for depth BLOCK_BATCH_DEPTH
// `getAuxMmrPeak(proofData, i)` is the peaks for depth BLOCK_BATCH_DEPTH - 1 - i
// 384 + 32 * 7 + 32 * 2 * i .. 384 + 32 * 7 + 32 * 2 * (i + 1): (32 bytes) as two uint128 cast to uint256, same as blockHash
// Note that the decreasing ordering is *different* than the convention in library MerkleMountainRange
function getAuxMmrPeak(bytes calldata proofData, uint256 i) pure returns (bytes32) {
    return bytes32(
        uint256(bytes32(proofData[AUX_PEAKS_START_IDX + i * 64:AUX_PEAKS_START_IDX + i * 64 + 32])) << 128
            | uint256(bytes32(proofData[AUX_PEAKS_START_IDX + i * 64 + 32:AUX_PEAKS_START_IDX + (i + 1) * 64]))
    );
}

/*
 * Constants for AxiomV2Query
 */

/// @dev Chain IDs for Ethereum mainnet and testnets
uint64 constant MAINNET_CHAIN_ID = 1;
uint64 constant GOERLI_CHAIN_ID = 5;
uint64 constant SEPOLIA_CHAIN_ID = 11_155_111;
uint64 constant HOLESKY_CHAIN_ID = 17_000;

/// @dev Constant recording the fact that this is Axiom V2
uint8 constant VERSION = 2;

/// @dev Largest deposit allowed at one time
uint256 constant MAX_DEPOSIT_SIZE = 100 ether;

/// @dev Conservative upper bound for `proofVerificationGas`.  Real values should be lower.
uint32 constant MAX_PROOF_VERIFICATION_GAS = 600_000;

/// @dev Conservative upper bound for `axiomQueryFee`. Real values should be lower.
uint256 constant MAX_AXIOM_QUERY_FEE = 0.05 ether;

File 10 of 22 : draft-IERC1822Upgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)

pragma solidity ^0.8.0;

/**
 * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
 * proxy whose upgrades are fully controlled by the current implementation.
 */
interface IERC1822ProxiableUpgradeable {
    /**
     * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
     * address.
     *
     * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
     * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
     * function revert if invoked through a proxy.
     */
    function proxiableUUID() external view returns (bytes32);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.3) (proxy/ERC1967/ERC1967Upgrade.sol)

pragma solidity ^0.8.2;

import "../beacon/IBeaconUpgradeable.sol";
import "../../interfaces/IERC1967Upgradeable.sol";
import "../../interfaces/draft-IERC1822Upgradeable.sol";
import "../../utils/AddressUpgradeable.sol";
import "../../utils/StorageSlotUpgradeable.sol";
import "../utils/Initializable.sol";

/**
 * @dev This abstract contract provides getters and event emitting update functions for
 * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
 *
 * _Available since v4.1._
 *
 * @custom:oz-upgrades-unsafe-allow delegatecall
 */
abstract contract ERC1967UpgradeUpgradeable is Initializable, IERC1967Upgradeable {
    function __ERC1967Upgrade_init() internal onlyInitializing {
    }

    function __ERC1967Upgrade_init_unchained() internal onlyInitializing {
    }
    // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
    bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;

    /**
     * @dev Storage slot with the address of the current implementation.
     * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
     * validated in the constructor.
     */
    bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;

    /**
     * @dev Returns the current implementation address.
     */
    function _getImplementation() internal view returns (address) {
        return StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value;
    }

    /**
     * @dev Stores a new address in the EIP1967 implementation slot.
     */
    function _setImplementation(address newImplementation) private {
        require(AddressUpgradeable.isContract(newImplementation), "ERC1967: new implementation is not a contract");
        StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
    }

    /**
     * @dev Perform implementation upgrade
     *
     * Emits an {Upgraded} event.
     */
    function _upgradeTo(address newImplementation) internal {
        _setImplementation(newImplementation);
        emit Upgraded(newImplementation);
    }

    /**
     * @dev Perform implementation upgrade with additional setup call.
     *
     * Emits an {Upgraded} event.
     */
    function _upgradeToAndCall(
        address newImplementation,
        bytes memory data,
        bool forceCall
    ) internal {
        _upgradeTo(newImplementation);
        if (data.length > 0 || forceCall) {
            _functionDelegateCall(newImplementation, data);
        }
    }

    /**
     * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
     *
     * Emits an {Upgraded} event.
     */
    function _upgradeToAndCallUUPS(
        address newImplementation,
        bytes memory data,
        bool forceCall
    ) internal {
        // Upgrades from old implementations will perform a rollback test. This test requires the new
        // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
        // this special case will break upgrade paths from old UUPS implementation to new ones.
        if (StorageSlotUpgradeable.getBooleanSlot(_ROLLBACK_SLOT).value) {
            _setImplementation(newImplementation);
        } else {
            try IERC1822ProxiableUpgradeable(newImplementation).proxiableUUID() returns (bytes32 slot) {
                require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
            } catch {
                revert("ERC1967Upgrade: new implementation is not UUPS");
            }
            _upgradeToAndCall(newImplementation, data, forceCall);
        }
    }

    /**
     * @dev Storage slot with the admin of the contract.
     * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
     * validated in the constructor.
     */
    bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;

    /**
     * @dev Returns the current admin.
     */
    function _getAdmin() internal view returns (address) {
        return StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value;
    }

    /**
     * @dev Stores a new address in the EIP1967 admin slot.
     */
    function _setAdmin(address newAdmin) private {
        require(newAdmin != address(0), "ERC1967: new admin is the zero address");
        StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
    }

    /**
     * @dev Changes the admin of the proxy.
     *
     * Emits an {AdminChanged} event.
     */
    function _changeAdmin(address newAdmin) internal {
        emit AdminChanged(_getAdmin(), newAdmin);
        _setAdmin(newAdmin);
    }

    /**
     * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
     * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
     */
    bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;

    /**
     * @dev Returns the current beacon.
     */
    function _getBeacon() internal view returns (address) {
        return StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value;
    }

    /**
     * @dev Stores a new beacon in the EIP1967 beacon slot.
     */
    function _setBeacon(address newBeacon) private {
        require(AddressUpgradeable.isContract(newBeacon), "ERC1967: new beacon is not a contract");
        require(
            AddressUpgradeable.isContract(IBeaconUpgradeable(newBeacon).implementation()),
            "ERC1967: beacon implementation is not a contract"
        );
        StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value = newBeacon;
    }

    /**
     * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
     * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
     *
     * Emits a {BeaconUpgraded} event.
     */
    function _upgradeBeaconToAndCall(
        address newBeacon,
        bytes memory data,
        bool forceCall
    ) internal {
        _setBeacon(newBeacon);
        emit BeaconUpgraded(newBeacon);
        if (data.length > 0 || forceCall) {
            _functionDelegateCall(IBeaconUpgradeable(newBeacon).implementation(), data);
        }
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function _functionDelegateCall(address target, bytes memory data) private returns (bytes memory) {
        require(AddressUpgradeable.isContract(target), "Address: delegate call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return AddressUpgradeable.verifyCallResult(success, returndata, "Address: low-level delegate call failed");
    }

    /**
     * @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;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.1) (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.
     *
     * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
     * constructor.
     *
     * Emits an {Initialized} event.
     */
    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.
     *
     * 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.
     *
     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
     * cannot be nested. If one is invoked in the context of another, execution will revert.
     *
     * 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.
     *
     * WARNING: setting the version to 255 will prevent any future reinitialization.
     *
     * Emits an {Initialized} event.
     */
    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.
     *
     * Emits an {Initialized} event the first time it is successfully executed.
     */
    function _disableInitializers() internal virtual {
        require(!_initializing, "Initializable: contract is initializing");
        if (_initialized < type(uint8).max) {
            _initialized = type(uint8).max;
            emit Initialized(type(uint8).max);
        }
    }

    /**
     * @dev Returns the highest version that has been initialized. See {reinitializer}.
     */
    function _getInitializedVersion() internal view returns (uint8) {
        return _initialized;
    }

    /**
     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
     */
    function _isInitializing() internal view returns (bool) {
        return _initializing;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)

pragma solidity ^0.8.0;

/**
 * @dev External interface of AccessControl declared to support ERC165 detection.
 */
interface IAccessControlUpgradeable {
    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     *
     * _Available since v3.1._
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call, an admin role
     * bearer except when using {AccessControl-_setupRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) external view returns (bool);

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {AccessControl-_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     */
    function renounceRole(bytes32 role, address account) external;
}

// 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;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)

pragma solidity ^0.8.0;

import "./math/MathUpgradeable.sol";

/**
 * @dev String operations.
 */
library StringsUpgradeable {
    bytes16 private constant _SYMBOLS = "0123456789abcdef";
    uint8 private constant _ADDRESS_LENGTH = 20;

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        unchecked {
            uint256 length = MathUpgradeable.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        unchecked {
            return toHexString(value, MathUpgradeable.log256(value) + 1);
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)

pragma solidity ^0.8.0;

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

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 *
 * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
 */
abstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable {
    function __ERC165_init() internal onlyInitializing {
    }

    function __ERC165_init_unchained() internal onlyInitializing {
    }
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165Upgradeable).interfaceId;
    }

    /**
     * @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 17 of 22 : IBeaconUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)

pragma solidity ^0.8.0;

/**
 * @dev This is the interface that {BeaconProxy} expects of its beacon.
 */
interface IBeaconUpgradeable {
    /**
     * @dev Must return an address that can be used as a delegate call target.
     *
     * {BeaconProxy} will check that this address is a contract.
     */
    function implementation() external view returns (address);
}

File 18 of 22 : IERC1967Upgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.3) (interfaces/IERC1967.sol)

pragma solidity ^0.8.0;

/**
 * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.
 *
 * _Available since v4.9._
 */
interface IERC1967Upgradeable {
    /**
     * @dev Emitted when the implementation is upgraded.
     */
    event Upgraded(address indexed implementation);

    /**
     * @dev Emitted when the admin account has changed.
     */
    event AdminChanged(address previousAdmin, address newAdmin);

    /**
     * @dev Emitted when the beacon is changed.
     */
    event BeaconUpgraded(address indexed beacon);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.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 functionCallWithValue(target, data, 0, "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");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, 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) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or 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 {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // 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);
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol)

pragma solidity ^0.8.0;

/**
 * @dev Library for reading and writing primitive types to specific storage slots.
 *
 * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
 * This library helps with reading and writing to such slots without the need for inline assembly.
 *
 * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
 *
 * Example usage to set ERC1967 implementation slot:
 * ```
 * contract ERC1967 {
 *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
 *
 *     function _getImplementation() internal view returns (address) {
 *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
 *     }
 *
 *     function _setImplementation(address newImplementation) internal {
 *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
 *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
 *     }
 * }
 * ```
 *
 * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
 */
library StorageSlotUpgradeable {
    struct AddressSlot {
        address value;
    }

    struct BooleanSlot {
        bool value;
    }

    struct Bytes32Slot {
        bytes32 value;
    }

    struct Uint256Slot {
        uint256 value;
    }

    /**
     * @dev Returns an `AddressSlot` with member `value` located at `slot`.
     */
    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
     */
    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
     */
    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
     */
    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library MathUpgradeable {
    enum Rounding {
        Down, // Toward negative infinity
        Up, // Toward infinity
        Zero // Toward zero
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds up instead
     * of rounding down.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
     * with further edits by Uniswap Labs also under MIT license.
     */
    function mulDiv(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod0 := mul(x, y)
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            require(denominator > prod1);

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
            // See https://cs.stackexchange.com/q/138556/92363.

            // Does not overflow because the denominator cannot be zero at this stage in the function.
            uint256 twos = denominator & (~denominator + 1);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
            // in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(
        uint256 x,
        uint256 y,
        uint256 denominator,
        Rounding rounding
    ) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10**64) {
                value /= 10**64;
                result += 64;
            }
            if (value >= 10**32) {
                value /= 10**32;
                result += 32;
            }
            if (value >= 10**16) {
                value /= 10**16;
                result += 16;
            }
            if (value >= 10**8) {
                value /= 10**8;
                result += 8;
            }
            if (value >= 10**4) {
                value /= 10**4;
                result += 4;
            }
            if (value >= 10**2) {
                value /= 10**2;
                result += 2;
            }
            if (value >= 10**1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256, rounded down, of a positive value.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165Upgradeable {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

Settings
{
  "remappings": [
    "@create3-factory/=lib/create3-factory/src/",
    "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
    "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
    "@solmate-utils/=lib/solmate/src/utils/",
    "create3-factory/=lib/create3-factory/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/",
    "nitro-contracts/=lib/nitro-contracts/src/",
    "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "solmate/=lib/solmate/src/",
    "weird-erc20/=lib/solmate/lib/weird-erc20/src/",
    "lib/create3-factory:ds-test/=lib/create3-factory/lib/forge-std/lib/ds-test/src/",
    "lib/create3-factory:forge-std/=lib/create3-factory/lib/forge-std/src/",
    "lib/create3-factory:solmate/=lib/create3-factory/lib/solmate/src/",
    "lib/forge-std:ds-test/=lib/forge-std/lib/ds-test/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 100000,
    "details": {
      "constantOptimizer": false,
      "yul": false
    }
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AggregateVkeyHashIsNotValid","type":"error"},{"inputs":[],"name":"AxiomHeaderVerifierAddressIsZero","type":"error"},{"inputs":[],"name":"AxiomProverAddressIsZero","type":"error"},{"inputs":[],"name":"AxiomQueryFeeIsTooLarge","type":"error"},{"inputs":[],"name":"CallbackHashDoesNotMatchQueryWitness","type":"error"},{"inputs":[],"name":"CanOnlyIncreaseGasOnActiveQuery","type":"error"},{"inputs":[],"name":"CannotFulfillFromOffchainIfNotInactive","type":"error"},{"inputs":[],"name":"CannotFulfillIfNotActive","type":"error"},{"inputs":[],"name":"CannotRefundBeforeDeadline","type":"error"},{"inputs":[],"name":"CannotRefundIfNotActive","type":"error"},{"inputs":[],"name":"CannotRefundIfNotRefundee","type":"error"},{"inputs":[],"name":"ComputeResultsHashDoesNotMatch","type":"error"},{"inputs":[],"name":"ContractIsFrozen","type":"error"},{"inputs":[],"name":"DepositAmountIsZero","type":"error"},{"inputs":[],"name":"DepositTooLarge","type":"error"},{"inputs":[],"name":"EscrowAmountExceedsBalance","type":"error"},{"inputs":[],"name":"GuardianAddressIsZero","type":"error"},{"inputs":[],"name":"InsufficientFunds","type":"error"},{"inputs":[],"name":"InsufficientGasForCallback","type":"error"},{"inputs":[],"name":"MaxFeePerGasIsTooLow","type":"error"},{"inputs":[],"name":"MinMaxFeePerGasIsZero","type":"error"},{"inputs":[],"name":"NewMaxQueryPriMustBeLargerThanPrevious","type":"error"},{"inputs":[],"name":"NotAxiomRole","type":"error"},{"inputs":[],"name":"NotProverRole","type":"error"},{"inputs":[],"name":"OnlyPayeeCanFulfillOffchainQuery","type":"error"},{"inputs":[],"name":"OnlyPayeeCanUnescrow","type":"error"},{"inputs":[],"name":"PayeeAddressIsZero","type":"error"},{"inputs":[],"name":"PayorAddressIsZero","type":"error"},{"inputs":[],"name":"ProofVerificationFailed","type":"error"},{"inputs":[],"name":"ProofVerificationGasIsTooLarge","type":"error"},{"inputs":[],"name":"ProverAddressIsZero","type":"error"},{"inputs":[],"name":"ProverNotAuthorized","type":"error"},{"inputs":[],"name":"QueryDeadlineIntervalIsTooLarge","type":"error"},{"inputs":[],"name":"QueryHashDoesNotMatchProof","type":"error"},{"inputs":[],"name":"QueryIsNotFulfilled","type":"error"},{"inputs":[],"name":"QueryIsNotInactive","type":"error"},{"inputs":[],"name":"SourceChainIdDoesNotMatch","type":"error"},{"inputs":[],"name":"TimelockAddressIsZero","type":"error"},{"inputs":[],"name":"UnescrowAmountExceedsEscrowedAmount","type":"error"},{"inputs":[],"name":"UnfreezeAddressIsZero","type":"error"},{"inputs":[],"name":"VerifierAddressIsZero","type":"error"},{"inputs":[],"name":"WithdrawalAmountExceedsFreeBalance","type":"error"},{"inputs":[],"name":"WithdrawalAmountIsZero","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"aggregateVkeyHash","type":"bytes32"}],"name":"AddAggregateVkeyHash","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"querySchema","type":"bytes32"},{"indexed":false,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"bytes32","name":"aggregateVkeyHash","type":"bytes32"}],"name":"AddPerQueryAggregateVkeyHash","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"querySchema","type":"bytes32"},{"indexed":false,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"address","name":"prover","type":"address"}],"name":"AddPerQueryProver","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"beacon","type":"address"}],"name":"BeaconUpgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"payor","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[],"name":"FreezeAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"queryId","type":"uint256"},{"indexed":false,"internalType":"bool","name":"callbackSucceeded","type":"bool"}],"name":"OffchainQueryFulfilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"queryId","type":"uint256"},{"indexed":true,"internalType":"address","name":"payor","type":"address"},{"indexed":false,"internalType":"uint32","name":"deadlineBlockNumber","type":"uint32"},{"indexed":false,"internalType":"uint64","name":"maxFeePerGas","type":"uint64"},{"indexed":false,"internalType":"uint32","name":"callbackGasLimit","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"QueryFeeInfoRecorded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"queryId","type":"uint256"},{"indexed":false,"internalType":"address","name":"payee","type":"address"},{"indexed":false,"internalType":"bool","name":"callbackSucceeded","type":"bool"}],"name":"QueryFulfilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"queryId","type":"uint256"},{"indexed":false,"internalType":"uint64","name":"maxFeePerGas","type":"uint64"},{"indexed":false,"internalType":"uint32","name":"callbackGasLimit","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"overrideAxiomQueryFee","type":"uint256"}],"name":"QueryGasIncreased","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"bytes32","name":"queryHash","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"queryId","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"userSalt","type":"bytes32"},{"indexed":false,"internalType":"address","name":"refundee","type":"address"},{"indexed":false,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"bytes","name":"extraData","type":"bytes"}],"name":"QueryInitiatedOnchain","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"bytes32","name":"queryHash","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"queryId","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"userSalt","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"ipfsHash","type":"bytes32"},{"indexed":false,"internalType":"address","name":"refundee","type":"address"},{"indexed":false,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"bytes","name":"extraData","type":"bytes"}],"name":"QueryInitiatedWithIpfsData","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"queryId","type":"uint256"},{"indexed":true,"internalType":"address","name":"refundee","type":"address"}],"name":"QueryRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"aggregateVkeyHash","type":"bytes32"}],"name":"RemoveAggregateVkeyHash","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"querySchema","type":"bytes32"},{"indexed":false,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"bytes32","name":"aggregateVkeyHash","type":"bytes32"}],"name":"RemovePerQueryAggregateVkeyHash","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"querySchema","type":"bytes32"},{"indexed":false,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"address","name":"prover","type":"address"}],"name":"RemovePerQueryProver","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"payor","type":"address"},{"indexed":true,"internalType":"uint256","name":"queryId","type":"uint256"},{"indexed":true,"internalType":"address","name":"payee","type":"address"},{"indexed":false,"internalType":"address","name":"refundee","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountUsed","type":"uint256"}],"name":"Unescrow","type":"event"},{"anonymous":false,"inputs":[],"name":"UnfreezeAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newAddress","type":"address"}],"name":"UpdateAxiomHeaderVerifierAddress","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newAddress","type":"address"}],"name":"UpdateAxiomProverAddress","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newAxiomQueryFee","type":"uint256"}],"name":"UpdateAxiomQueryFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"newMinMaxFeePerGas","type":"uint64"}],"name":"UpdateMinMaxFeePerGas","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"newProofVerificationGas","type":"uint32"}],"name":"UpdateProofVerificationGas","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"newQueryDeadlineInterval","type":"uint32"}],"name":"UpdateQueryDeadlineInterval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newAddress","type":"address"}],"name":"UpdateVerifierAddress","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"payor","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"payee","type":"address"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"AXIOM_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GUARDIAN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PROVER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TIMELOCK_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNFREEZE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_aggregateVkeyHash","type":"bytes32"}],"name":"addAggregateVkeyHash","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"querySchema","type":"bytes32"},{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes32","name":"aggregateVkeyHash","type":"bytes32"}],"name":"addPerQueryAggregateVkeyHash","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"querySchema","type":"bytes32"},{"internalType":"address","name":"target","type":"address"},{"internalType":"address","name":"prover","type":"address"}],"name":"addPerQueryProver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"aggregateVkeyHashes","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"axiomHeaderVerifierAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"axiomQueryFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balances","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"payor","type":"address"}],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"freezeAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"frozen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"snapshotPmmrSize","type":"uint32"},{"internalType":"bytes32[]","name":"proofMmrPeaks","type":"bytes32[]"},{"internalType":"bytes32[]","name":"mmrComplementOrPeaks","type":"bytes32[]"}],"internalType":"struct IAxiomV2HeaderVerifier.MmrWitness","name":"mmrWitness","type":"tuple"},{"internalType":"bytes32[]","name":"computeResults","type":"bytes32[]"},{"internalType":"bytes","name":"proof","type":"bytes"},{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct IAxiomV2Query.AxiomV2Callback","name":"callback","type":"tuple"},{"internalType":"bytes32","name":"userSalt","type":"bytes32"}],"name":"fulfillOffchainQuery","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"snapshotPmmrSize","type":"uint32"},{"internalType":"bytes32[]","name":"proofMmrPeaks","type":"bytes32[]"},{"internalType":"bytes32[]","name":"mmrComplementOrPeaks","type":"bytes32[]"}],"internalType":"struct IAxiomV2HeaderVerifier.MmrWitness","name":"mmrWitness","type":"tuple"},{"internalType":"bytes32[]","name":"computeResults","type":"bytes32[]"},{"internalType":"bytes","name":"proof","type":"bytes"},{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct IAxiomV2Query.AxiomV2Callback","name":"callback","type":"tuple"},{"components":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"bytes32","name":"userSalt","type":"bytes32"},{"internalType":"bytes32","name":"queryHash","type":"bytes32"},{"internalType":"bytes32","name":"callbackHash","type":"bytes32"},{"internalType":"address","name":"refundee","type":"address"}],"internalType":"struct IAxiomV2Query.AxiomV2QueryWitness","name":"queryWitness","type":"tuple"}],"name":"fulfillQuery","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"queryId","type":"uint256"},{"internalType":"uint64","name":"newMaxFeePerGas","type":"uint64"},{"internalType":"uint32","name":"newCallbackGasLimit","type":"uint32"},{"internalType":"uint256","name":"overrideAxiomQueryFee","type":"uint256"}],"name":"increaseQueryGas","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"axiomHeaderVerifierAddress","type":"address"},{"internalType":"address","name":"verifierAddress","type":"address"},{"internalType":"address[]","name":"proverAddresses","type":"address[]"},{"internalType":"bytes32[]","name":"aggregateVkeyHashes","type":"bytes32[]"},{"internalType":"uint32","name":"queryDeadlineInterval","type":"uint32"},{"internalType":"uint32","name":"proofVerificationGas","type":"uint32"},{"internalType":"uint256","name":"axiomQueryFee","type":"uint256"},{"internalType":"uint64","name":"minMaxFeePerGas","type":"uint64"},{"internalType":"uint32","name":"maxQueryDeadlineInterval","type":"uint32"},{"internalType":"address","name":"timelock","type":"address"},{"internalType":"address","name":"guardian","type":"address"},{"internalType":"address","name":"unfreeze","type":"address"}],"internalType":"struct IAxiomV2Query.AxiomV2QueryInit","name":"init","type":"tuple"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"maxQueryDeadlineInterval","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minMaxFeePerGas","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"address","name":"","type":"address"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"perQueryAggregateVkeyHashes","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"perQueryProvers","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proofVerificationGas","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"queries","outputs":[{"internalType":"uint8","name":"state","type":"uint8"},{"internalType":"uint32","name":"deadlineBlockNumber","type":"uint32"},{"internalType":"uint32","name":"callbackGasLimit","type":"uint32"},{"internalType":"address","name":"payee","type":"address"},{"internalType":"uint256","name":"payment","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"queryDeadlineInterval","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"bytes32","name":"userSalt","type":"bytes32"},{"internalType":"bytes32","name":"queryHash","type":"bytes32"},{"internalType":"bytes32","name":"callbackHash","type":"bytes32"},{"internalType":"address","name":"refundee","type":"address"}],"internalType":"struct IAxiomV2Query.AxiomV2QueryWitness","name":"queryWitness","type":"tuple"}],"name":"refundQuery","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_aggregateVkeyHash","type":"bytes32"}],"name":"removeAggregateVkeyHash","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"querySchema","type":"bytes32"},{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes32","name":"aggregateVkeyHash","type":"bytes32"}],"name":"removePerQueryAggregateVkeyHash","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"querySchema","type":"bytes32"},{"internalType":"address","name":"target","type":"address"},{"internalType":"address","name":"prover","type":"address"}],"name":"removePerQueryProver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"sourceChainId","type":"uint64"},{"internalType":"bytes32","name":"dataQueryHash","type":"bytes32"},{"components":[{"internalType":"uint8","name":"k","type":"uint8"},{"internalType":"uint16","name":"resultLen","type":"uint16"},{"internalType":"bytes32[]","name":"vkey","type":"bytes32[]"},{"internalType":"bytes","name":"computeProof","type":"bytes"}],"internalType":"struct IAxiomV2Query.AxiomV2ComputeQuery","name":"computeQuery","type":"tuple"},{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct IAxiomV2Query.AxiomV2Callback","name":"callback","type":"tuple"},{"components":[{"internalType":"uint64","name":"maxFeePerGas","type":"uint64"},{"internalType":"uint32","name":"callbackGasLimit","type":"uint32"},{"internalType":"uint256","name":"overrideAxiomQueryFee","type":"uint256"}],"internalType":"struct IAxiomV2Query.AxiomV2FeeData","name":"feeData","type":"tuple"},{"internalType":"bytes32","name":"userSalt","type":"bytes32"},{"internalType":"address","name":"refundee","type":"address"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"sendQuery","outputs":[{"internalType":"uint256","name":"queryId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"queryHash","type":"bytes32"},{"internalType":"bytes32","name":"ipfsHash","type":"bytes32"},{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct IAxiomV2Query.AxiomV2Callback","name":"callback","type":"tuple"},{"components":[{"internalType":"uint64","name":"maxFeePerGas","type":"uint64"},{"internalType":"uint32","name":"callbackGasLimit","type":"uint32"},{"internalType":"uint256","name":"overrideAxiomQueryFee","type":"uint256"}],"internalType":"struct IAxiomV2Query.AxiomV2FeeData","name":"feeData","type":"tuple"},{"internalType":"bytes32","name":"userSalt","type":"bytes32"},{"internalType":"address","name":"refundee","type":"address"}],"name":"sendQueryWithIpfsData","outputs":[{"internalType":"uint256","name":"queryId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"bytes32","name":"userSalt","type":"bytes32"},{"internalType":"bytes32","name":"queryHash","type":"bytes32"},{"internalType":"bytes32","name":"callbackHash","type":"bytes32"},{"internalType":"address","name":"refundee","type":"address"}],"internalType":"struct IAxiomV2Query.AxiomV2QueryWitness","name":"queryWitness","type":"tuple"},{"internalType":"uint256","name":"amountUsed","type":"uint256"}],"name":"unescrow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unfreezeAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_axiomHeaderVerifierAddress","type":"address"}],"name":"updateAxiomHeaderVerifierAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_axiomQueryFee","type":"uint256"}],"name":"updateAxiomQueryFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"_minMaxFeePerGas","type":"uint64"}],"name":"updateMinMaxFeePerGas","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_proofVerificationGas","type":"uint32"}],"name":"updateProofVerificationGas","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_queryDeadlineInterval","type":"uint32"}],"name":"updateQueryDeadlineInterval","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_verifierAddress","type":"address"}],"name":"updateVerifierAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"}],"name":"upgradeTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"verifierAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address payable","name":"payee","type":"address"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60a0604052306080523480156200001557600080fd5b506200002062000026565b62000164565b600054610100900460ff161562000074576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016200006b90620000ec565b60405180910390fd5b60005460ff9081161015620000ea57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff9081179091556040517f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249891620000e19162000154565b60405180910390a15b565b602080825281016200014e81602781527f496e697469616c697a61626c653a20636f6e747261637420697320696e69746960208201527f616c697a696e6700000000000000000000000000000000000000000000000000604082015260600190565b92915050565b60ff82168152602081016200014e565b608051615ff86200019c600039600081816110120152818161106c0152818161142a0152818161148401526115730152615ff86000f3fe60806040526004361061033e5760003560e01c8063639a6c2b116101b0578063c4bf9ea4116100ec578063debebe0411610095578063f288a2e21161006f578063f288a2e214610a9c578063f340fa0114610ad0578063f5ac134d14610ae3578063fb035bc314610b0d57600080fd5b8063debebe0414610a47578063e3613d7314610a5a578063ed2d9ba014610a8957600080fd5b8063d547741f116100c6578063d547741f146109d3578063d77de079146109f3578063dc9a4ef614610a1357600080fd5b8063c4bf9ea41461095f578063c608b5e81461097f578063c70cb102146109b357600080fd5b806380b79a671161015957806399464c891161013357806399464c891461088b578063a217fddf146108a0578063ab9c67ad146108b5578063b16033911461093f57600080fd5b806380b79a67146107f857806391d148541461081857806396698cc51461086b57600080fd5b8063736f16181161018a578063736f1618146107965780637393da9e146107b657806379ce0468146107cd57600080fd5b8063639a6c2b1461074157806366c5c4a0146107615780636ee9a0d51461077657600080fd5b80632aae79331161027f5780633e48a08711610228578063469b236211610202578063469b2362146106d85780634a253074146107065780634f1ef2861461071957806352d1902d1461072c57600080fd5b80633e48a0871461067857806341ae4059146106985780634415fe46146106b857600080fd5b80633237c2fd116102595780633237c2fd1461061857806336568abe146106385780633659cfe61461065857600080fd5b80632aae7933146105a45780632b7d2bad146105c45780632f2ff15d146105f857600080fd5b80630c2d17bb116102ec57806324ea54f4116102c657806324ea54f4146104e057806327e235e31461051457806328e80f47146105425780632a80f0f21461058457600080fd5b80630c2d17bb1461044857806318bdffbb14610468578063248a9ca3146104a357600080fd5b806304d295a21161031d57806304d295a2146103dd578063054f7d9c146103fd57806306fb89fa1461041757600080fd5b8062f714ce1461034357806301ffc9a714610365578063028ad6e11461039b575b600080fd5b34801561034f57600080fd5b5061036361035e3660046145da565b610b33565b005b34801561037157600080fd5b5061038561038036600461464a565b610c8f565b6040516103929190614675565b60405180910390f35b3480156103a757600080fd5b506103856103b6366004614683565b61012760209081526000938452604080852082529284528284209052825290205460ff1681565b3480156103e957600080fd5b506103636103f8366004614683565b610ceb565b34801561040957600080fd5b506097546103859060ff1681565b34801561042357600080fd5b506103856104323660046146d3565b6101266020526000908152604090205460ff1681565b34801561045457600080fd5b506103636104633660046146d3565b610db8565b34801561047457600080fd5b50610125546104969073ffffffffffffffffffffffffffffffffffffffff1681565b60405161039291906146fd565b3480156104af57600080fd5b506104d36104be3660046146d3565b60009081526065602052604090206001015490565b6040516103929190614711565b3480156104ec57600080fd5b506104d37f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a504181565b34801561052057600080fd5b506104d361052f36600461471f565b61012d6020526000908152604090205481565b34801561054e57600080fd5b5061038561055d366004614740565b61012860209081526000938452604080852082529284528284209052825290205460ff1681565b34801561059057600080fd5b5061036361059f366004614740565b610def565b3480156105b057600080fd5b506103636105bf3660046146d3565b610eb2565b3480156105d057600080fd5b506104d37f542178611b653a605b79640db9b52a7afa591d6ace75cd36686e0ee264f4f57281565b34801561060457600080fd5b506103636106133660046145da565b610f3c565b34801561062457600080fd5b5061036361063336600461471f565b610f66565b34801561064457600080fd5b506103636106533660046145da565b610f99565b34801561066457600080fd5b5061036361067336600461471f565b610ffb565b34801561068457600080fd5b5061036361069336600461479d565b611154565b3480156106a457600080fd5b506103636106b3366004614683565b611187565b3480156106c457600080fd5b506103636106d33660046147d9565b611243565b3480156106e457600080fd5b50610124546104969073ffffffffffffffffffffffffffffffffffffffff1681565b6103636107143660046147fa565b611276565b6103636107273660046149ae565b611413565b34801561073857600080fd5b506104d3611559565b34801561074d57600080fd5b5061036361075c366004614740565b6115ef565b34801561076d57600080fd5b506103636116af565b34801561078257600080fd5b50610363610791366004614ac9565b61172d565b3480156107a257600080fd5b506103636107b136600461471f565b6119fd565b3480156107c257600080fd5b506104d361012a5481565b3480156107d957600080fd5b50610129546107eb9063ffffffff1681565b6040516103929190614bc1565b34801561080457600080fd5b50610363610813366004614be5565b611a30565b34801561082457600080fd5b506103856108333660046145da565b600091825260656020908152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b34801561087757600080fd5b50610363610886366004614c35565b611f4f565b34801561089757600080fd5b50610363612150565b3480156108ac57600080fd5b506104d3600081565b3480156108c157600080fd5b5061092e6108d03660046146d3565b61012c602052600090815260409020805460019091015460ff82169163ffffffff61010082048116926501000000000083049091169173ffffffffffffffffffffffffffffffffffffffff6901000000000000000000909104169085565b604051610392959493929190614c71565b34801561094b57600080fd5b5061036361095a3660046146d3565b6121d1565b34801561096b57600080fd5b5061036361097a366004614cbd565b612204565b34801561098b57600080fd5b506104d37ff4e710c64967f31ba1090db2a7dd9e704155d00947ce853da47446cb68ee65da81565b3480156109bf57600080fd5b506103636109ce366004614d9b565b6125bc565b3480156109df57600080fd5b506103636109ee3660046145da565b61277b565b3480156109ff57600080fd5b50610363610a0e36600461479d565b6127a0565b348015610a1f57600080fd5b506104d37f60044782a422109ac08a415e44260ad5d3bad63d96ebe1fac0363399642ee3f281565b6104d3610a55366004614dbc565b6127d3565b348015610a6657600080fd5b5061012b54610a7c9067ffffffffffffffff1681565b6040516103929190614e72565b6104d3610a97366004614e95565b6128dc565b348015610aa857600080fd5b506104d37ff66846415d2bf9eabda9e84793ff9c0ea96d87f50fc41e66aa16469c6a442f0581565b610363610ade36600461471f565b612c06565b348015610aef57600080fd5b5061012b546107eb9068010000000000000000900463ffffffff1681565b348015610b1957600080fd5b50610129546107eb90640100000000900463ffffffff1681565b73ffffffffffffffffffffffffffffffffffffffff8116610b80576040517f2f8a6f2200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600090815261012d6020526040902054821115610bca576040517ff7a7a59500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81600003610c04576040517fccb1e81400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600090815261012d6020526040902080548390039055610c3b73ffffffffffffffffffffffffffffffffffffffff821683612c9f565b3373ffffffffffffffffffffffffffffffffffffffff167f56c54ba9bd38d8fd62012e42c7ee564519b09763c426d331b3661b537ead19b28383604051610c83929190614fbe565b60405180910390a25050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7132f8a9000000000000000000000000000000000000000000000000000000001480610ce55750610ce582612d7c565b92915050565b7ff66846415d2bf9eabda9e84793ff9c0ea96d87f50fc41e66aa16469c6a442f05610d1581612e13565b60008481526101276020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845282528083208584529091529081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555184907f2985d9844f1c5cfc77069b4f176964ff8687324b391d3b394a164024d602135d90610daa9086908690614fd9565b60405180910390a250505050565b7ff66846415d2bf9eabda9e84793ff9c0ea96d87f50fc41e66aa16469c6a442f05610de281612e13565b610deb82612e1d565b5050565b7ff66846415d2bf9eabda9e84793ff9c0ea96d87f50fc41e66aa16469c6a442f05610e1981612e13565b60008481526101286020908152604080832073ffffffffffffffffffffffffffffffffffffffff808816855290835281842090861684529091529081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555184907fa9611403ffbf5e30519e911927c5f3566e7661a8f9640ffefd7fde30b7319d0690610daa9086908690614ff4565b7ff66846415d2bf9eabda9e84793ff9c0ea96d87f50fc41e66aa16469c6a442f05610edc81612e13565b6000828152610126602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555183917fb878feae2e86bc3890d16dda54077e7ef0e0ffbacd789b2c258b92493e7d28d591a25050565b600082815260656020526040902060010154610f5781612e13565b610f618383612e7f565b505050565b7ff66846415d2bf9eabda9e84793ff9c0ea96d87f50fc41e66aa16469c6a442f05610f9081612e13565b610deb82612f73565b73ffffffffffffffffffffffffffffffffffffffff81163314610ff1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fe89061506c565b60405180910390fd5b610deb828261303c565b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016300361106a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fe8906150d6565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166110df7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff161461112c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fe890615140565b611135816130f7565b6040805160008082526020820190925261115191839190613121565b50565b7ff66846415d2bf9eabda9e84793ff9c0ea96d87f50fc41e66aa16469c6a442f0561117e81612e13565b610deb82613274565b7ff66846415d2bf9eabda9e84793ff9c0ea96d87f50fc41e66aa16469c6a442f056111b181612e13565b60008481526101276020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845282528083208584529091529081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555184907f9034eb299f78da99651eea0f72d646742962b9d29fe8fbbf25ab0de0fd9a678e90610daa9086908690614fd9565b7ff66846415d2bf9eabda9e84793ff9c0ea96d87f50fc41e66aa16469c6a442f0561126d81612e13565b610deb8261331f565b61127e6133c8565b600084815261012c60205260409020805460ff166001146112cb576040517f3d1c563c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61012b5467ffffffffffffffff9081169085161015611316576040517f25a8b6d700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600181015461012a548084111561132a5750825b6000611337878784613407565b9050828111611372576040517f9eca72e200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b828103348111156113af576040517f356680b700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b818560010181905550887f25ffed1d7b3823d2e30120aec66c9ccaad42f93ab6d1537ba9d785a2e446f4d08989896040516113ec93929190615150565b60405180910390a2803411156114085761140833823403613454565b505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163003611482576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fe8906150d6565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166114f77f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614611544576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fe890615140565b61154d826130f7565b610deb82826001613121565b60003073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146115ca576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fe8906151d2565b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc90565b7ff66846415d2bf9eabda9e84793ff9c0ea96d87f50fc41e66aa16469c6a442f0561161981612e13565b60008481526101286020908152604080832073ffffffffffffffffffffffffffffffffffffffff808816855290835281842090861684529091529081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555184907f8486629005b3a257ef75d8acf26fdbc2127e21a2b2fe401e18e938e76d02fc0690610daa9086908690614ff4565b7ff4e710c64967f31ba1090db2a7dd9e704155d00947ce853da47446cb68ee65da6116d981612e13565b609780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556040517fe6fdbf73945dd61794a752b9181ea29f77170a7b1ffd37e0a7ff9d2c6f7258b990600090a150565b6117356133c8565b600061177888868661174a602088018861471f565b8b8b60405160200161175d929190615238565b604051602081830303815290604052805190602001206134f3565b6020808201519192506000916117d2916117949087018761471f565b6117a16020880188615245565b6040516020016117b3939291906152f7565b6040516020818303038152906040528051906020012085600033613a34565b600081815261012c6020526040902080549192509060ff1615611821576040517fab70a5d400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606083015173ffffffffffffffffffffffffffffffffffffffff163314611874576040517f73c3cc3a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660021781556000806118ad602088018861471f565b73ffffffffffffffffffffffffffffffffffffffff16146119b857835160408501516000917f8193399c00000000000000000000000000000000000000000000000000000000913390878f8f61190660208f018f615245565b60405160240161191d989796959493929190615369565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925291506119b4906119ad9089018961471f565b5a83613a91565b9150505b827fee6b24cc42698e8355f8a268e7237b2db8c755fe5ecc21e9ffe4e667b5825d94826040516119e89190614675565b60405180910390a25050505050505050505050565b7ff66846415d2bf9eabda9e84793ff9c0ea96d87f50fc41e66aa16469c6a442f05611a2781612e13565b610deb82613aa9565b600054610100900460ff1615808015611a505750600054600160ff909116105b80611a6a5750303b158015611a6a575060005460ff166001145b611aa0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fe89061542e565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558015611afe57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b611b06613b67565b611b0e613ba8565b6000611b226101408401610120850161471f565b73ffffffffffffffffffffffffffffffffffffffff1603611b6f576040517fd5ae8cf700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611b836101608401610140850161471f565b73ffffffffffffffffffffffffffffffffffffffff1603611bd0576040517f40c2354200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611be46101808401610160850161471f565b73ffffffffffffffffffffffffffffffffffffffff1603611c31576040517f6d92bcf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611c46611c41602084018461471f565b612f73565b611c5e611c59604084016020850161471f565b613aa9565b60005b611c6e606084018461543e565b9050811015611cab57611ca3611c87606085018561543e565b83818110611c9757611c976154b1565b90506020020135612e1d565b600101611c61565b50611cbe6101208301610100840161479d565b61012b805463ffffffff9290921668010000000000000000027fffffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffff909216919091179055611d19611d1460a084016080850161479d565b613c13565b611d31611d2c60c0840160a0850161479d565b613274565b611d3e8260c00135613cc7565b611d57611d52610100840160e085016147d9565b61331f565b611d736000611d6e6101408501610120860161471f565b612e7f565b611da97ff66846415d2bf9eabda9e84793ff9c0ea96d87f50fc41e66aa16469c6a442f05611d6e6101408501610120860161471f565b611ddf7f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a5041611d6e6101608501610140860161471f565b611e157ff4e710c64967f31ba1090db2a7dd9e704155d00947ce853da47446cb68ee65da611d6e6101808501610160860161471f565b6000805b611e26604085018561543e565b9050811015611ee257611e3c604085018561543e565b82818110611e4c57611e4c6154b1565b9050602002016020810190611e61919061471f565b915073ffffffffffffffffffffffffffffffffffffffff8216611eb0576040517ffbc5fc2f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611eda7f60044782a422109ac08a415e44260ad5d3bad63d96ebe1fac0363399642ee3f283612e7f565b600101611e19565b50508015610deb57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1690556040517f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890611f43906001906154f4565b60405180910390a15050565b611f576133c8565b6000611f6960a084016080850161471f565b90506000611f9260408501356060860135602087018035908690611f8d908a61471f565b613a34565b600081815261012c6020526040902080549192509060ff16600214611fe3576040517f14532a0c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600181015480851115612022576040517f1d8b710000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81546901000000000000000000900473ffffffffffffffffffffffffffffffffffffffff16338114612080576040517f55d9010000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600317835573ffffffffffffffffffffffffffffffffffffffff808216600081815261012d6020908152604080832080548c019055938916825292902080548986030190559085906120f8908a018a61471f565b73ffffffffffffffffffffffffffffffffffffffff167f498fc64c3c7f25c2a420d7cbf8f6e5e9f63b033b11a621d30e4a9119587ede65888a60405161213f929190614fd9565b60405180910390a450505050505050565b7f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a504161217a81612e13565b609780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556040517f61340a1b154d5d21d259a74bf95379201799b9d12cc6509bb46cb56dc281df5590600090a150565b7ff66846415d2bf9eabda9e84793ff9c0ea96d87f50fc41e66aa16469c6a442f056121fb81612e13565b610deb82613cc7565b61220c6133c8565b600061222188868661174a602088018861471f565b9050600061225460408401356060850135602086013561224760a088016080890161471f565b611f8d602089018961471f565b9050612263602085018561471f565b6122706020860186615245565b604051602001612282939291906152f7565b604051602081830303815290604052805190602001208360600135146122d4576040517f521bdd1100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160200151836040013514612315576040517faed145d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600081815261012c60205260409020805460ff16600114612362576040517ff8c22cf100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606083015181547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0073ffffffffffffffffffffffffffffffffffffffff909216690100000000000000000002919091167fffffff0000000000000000000000000000000000000000ffffffffffffffff009091161760021781556000806123ec602088018861471f565b73ffffffffffffffffffffffffffffffffffffffff16146125865783516000907fdc5cd53c000000000000000000000000000000000000000000000000000000009061243b602089018961471f565b6040880151878f8f61245060208f018f615245565b604051602401612467989796959493929190615369565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092528454909250603f916125069163ffffffff650100000000009091041690615531565b6125109190615597565b63ffffffff1661012c5a61252491906155b5565b1161255b576040517f657989e900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61258261256b602089018961471f565b845465010000000000900463ffffffff1683613a91565b9150505b827ff5abe1a043591aece5d845c5d02d67e11824a16bfdb48b9d7934486e3bef95a98560600151836040516119e89291906155c8565b6125c46133c8565b60006125d660a083016080840161471f565b905060006125fa60408401356060850135602086018035908690611f8d908961471f565b90503373ffffffffffffffffffffffffffffffffffffffff83161461264b576040517f6464486800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600081815261012c60205260409020805460ff16600114612698576040517f5f158cf700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8054610100900463ffffffff1643116126dd576040517f6d542c0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018082015473ffffffffffffffffffffffffffffffffffffffff8516600081815261012d60209081526040808320805490950190945586825261012c905282812080547fffffff00000000000000000000000000000000000000000000000000000000001681559093018390559051909184917f800e41f8023d1b860a629dfe2b3fc12d34767238ec1b02f5f7e8a3475b9dadf69190a350505050565b60008281526065602052604090206001015461279681612e13565b610f61838361303c565b7ff66846415d2bf9eabda9e84793ff9c0ea96d87f50fc41e66aa16469c6a442f056127ca81612e13565b610deb82613c13565b60006127dd6133c8565b73ffffffffffffffffffffffffffffffffffffffff82166127fc573391505b61284a8761280d602088018861471f565b61281a6020890189615245565b60405160200161282c939291906152f7565b60405160208183030381529060405280519060200120858533613a34565b90506128778161285d60208701876147d9565b61286d604088016020890161479d565b8760400135613d3e565b8087337ff3a2958f23705cbc6bbc0922c0af3c82b76d93e8acc5c17ef86736cf4563fb85868a876128ab60208d018d61471f565b6128b860208e018e615245565b6040516128ca969594939291906155e3565b60405180910390a49695505050505050565b60006128e66133c8565b61012460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663fe428ed36040518163ffffffff1660e01b8152600401602060405180830381865afa158015612954573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129789190615642565b67ffffffffffffffff168a67ffffffffffffffff16146129c4576040517f0db21db600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff84166129e3573393505b60006129f260208a018a615677565b60ff16600003612a4e5760028b8b612a0d60208d018d615677565b612a1d60408e0160208f016156ad565b604051602001612a3195949392919061571e565b604051602081830303815290604052805190602001209050612b21565b6000612a5d60208b018b615677565b612a6d60408c0160208d016156ad565b612a7a60408d018d61543e565b9050612a8960408e018e61543e565b604051602001612a9d959493929190615777565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052905060028c8c83612adf60608f018f615245565b90508e8060600190612af19190615245565b604051602001612b079796959493929190615820565b604051602081830303815290604052805190602001209150505b612b6f81612b3260208b018b61471f565b612b3f60208c018c615245565b604051602001612b51939291906152f7565b60405160208183030381529060405280519060200120888833613a34565b9150612b9c82612b8260208a018a6147d9565b612b9260408b0160208c0161479d565b8a60400135613d3e565b8181337fb72b05c090ac4ae9ec18b7e708d597093716f98567026726f6f5d9f1723161788989612bcf60208f018f61471f565b8e8060200190612bdf9190615245565b604051612bf0959493929190615886565b60405180910390a4509998505050505050505050565b612c0e6133c8565b73ffffffffffffffffffffffffffffffffffffffff8116612c5b576040517f3422bc3900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b34600003612c95576040517f0ddbd93400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6111518134613454565b80471015612cd9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fe8906158f8565b60008273ffffffffffffffffffffffffffffffffffffffff1682604051612cff90615908565b60006040518083038185875af1925050503d8060008114612d3c576040519150601f19603f3d011682016040523d82523d6000602084013e612d41565b606091505b5050905080610f61576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fe89061596a565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610ce557507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610ce5565b6111518133614030565b6000818152610126602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555182917fcf6ab1ad888a23cab770a17862e882b2a503fecaa716a2c147d43692db6762d991a250565b600082815260656020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610deb57600082815260656020908152604080832073ffffffffffffffffffffffffffffffffffffffff85168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055612f153390565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b73ffffffffffffffffffffffffffffffffffffffff8116612fc0576040517ff270e94a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61012480547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83161790556040517f75bcc4f3a8eeec60c22df746d7f53083c892df4b1e07b2be152f117df8f353f7906130319083906146fd565b60405180910390a150565b600082815260656020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff1615610deb57600082815260656020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b7ff66846415d2bf9eabda9e84793ff9c0ea96d87f50fc41e66aa16469c6a442f05610deb81612e13565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff161561315457610f61836140ea565b8273ffffffffffffffffffffffffffffffffffffffff166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156131d9575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682019092526131d691810190615985565b60015b61320f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fe890615a00565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8114613268576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fe890615a6a565b50610f6183838361419e565b620927c063ffffffff821611156132b7576040517f916551ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61012980547fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff1664010000000063ffffffff8416021790556040517fd2d353df76578044ea52bec30dc61526b5546fb34503457fa20b79e4fdcde32e90613031908390614bc1565b8067ffffffffffffffff16600003613363576040517f20a88e0100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61012b80547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff83161790556040517f2c69ced866ae8fc3b771915857e877d4bf0153be881ca6b53b004c47db57131c90613031908390614e72565b60975460ff1615613405576040517f379dfc6300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b61012954600090829061342890640100000000900463ffffffff1685615a7a565b6134389063ffffffff1686615a9a565b67ffffffffffffffff1661344c9190615ac9565b949350505050565b68056bc75e2d63100000811115613497576040517fc56d46d300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216600081815261012d602052604090819020805484019055517fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c90610c83908490614711565b6040805160808101825260008082526020820181905291810182905260608101919091526135276101a06101808688615adc565b61353091615b0c565b67ffffffffffffffff168152600061354e6101e06101c08789615adc565b61355791615b0c565b60806135696101c06101a0898b615adc565b61357291615b0c565b901b1790506135876102206102008789615adc565b61359091615b0c565b60806135a26102006101e0898b615adc565b6135ab91615b0c565b901b1760208301526135c36102606102408789615adc565b6135cc91615b0c565b60806135de610240610220898b615adc565b6135e791615b0c565b901b17604083015260006136016102a0610280888a615adc565b61360a91615b0c565b608061361c6102806102608a8c615adc565b61362591615b0c565b901b179050600061363c6102c06102a0898b615adc565b61364591615b0c565b90506136576102e06102c0898b615adc565b61366091615b0c565b73ffffffffffffffffffffffffffffffffffffffff9081166060860152610124546040517fedc55b94000000000000000000000000000000000000000000000000000000008152911690819063edc55b94906136c29086908e90600401615c35565b600060405180830381600087803b1580156136dc57600080fd5b505af11580156136f0573d6000803e3d6000fd5b505050508073ffffffffffffffffffffffffffffffffffffffff1663fe428ed36040518163ffffffff1660e01b8152600401602060405180830381865afa15801561373f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137639190615642565b67ffffffffffffffff16856000015167ffffffffffffffff16146137b3576040517f0db21db600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8584146137ec576040517f921c328700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081527f16d6d09ad43c2e13327e8e85b0f16a19ef2e63b72c391bfd77d21c5d49902185602052604090205460ff16806138725750600080527f16d6d09ad43c2e13327e8e85b0f16a19ef2e63b72c391bfd77d21c5d499021856020527fdf4fae2a9d03ddefae2c9e431bd1ae49d400972b66abd41187abff73623b3c4b5460ff165b806138b757506040808601516000908152610128602090815282822073ffffffffffffffffffffffffffffffffffffffff8b16835281528282203383529052205460ff165b6138ed576040517fa822f97100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152610126602052604090205460ff168061394557506040808601516000908152610127602090815282822073ffffffffffffffffffffffffffffffffffffffff8b16835281528282208583529052205460ff165b61397b576040517febe1d07800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101255460405160009173ffffffffffffffffffffffffffffffffffffffff16906139a9908c908c90615c55565b6000604051808303816000865af19150503d80600081146139e6576040519150601f19603f3d011682016040523d82523d6000602084013e6139eb565b606091505b5050905080613a26576040517fd611c31800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505095945050505050565b6000468285888887604051602001613a5196959493929190615c62565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101209695505050505050565b600080600083516020850160008888f1949350505050565b73ffffffffffffffffffffffffffffffffffffffff8116613af6576040517f3815ff6600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61012580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83161790556040517fe6e1c2bf73bb6cc1c20546306996ac2050af3e2cfc8d64d3173c7ef0ce549519906130319083906146fd565b600054610100900460ff16613405576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fe890615d26565b600054610100900460ff16613be9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fe890615d26565b609780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b61012b5463ffffffff6801000000000000000090910481169082161115613c66576040517fb2de8d0000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61012980547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff83161790556040517f266d22101c27a330937ff06442e5289e92a84a449d22bb001c03789f7774b62890613031908390614bc1565b66b1a2bc2ec50000811115613d08576040517ff729a96300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61012a8190556040517f1a520c8da72d8b5ebd7db613f55b33d3186f12b647fe2c197cd27bb2840b277690613031908390614711565b600084815261012c602052604090205460ff1615613d88576040517fcaa9c69700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61012b5467ffffffffffffffff9081169084161015613dd3576040517f25a8b6d700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61012a5480821115613de25750805b6000613def858584613407565b9050803414613e6e573415613e0857613e083334613454565b33600090815261012d602052604090205480821115613e53576040517f0fa9f54b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600090815261012d60205260409020908290039055613eb1565b68056bc75e2d63100000341115613eb1576040517fc56d46d300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610129546040805160a081019091526001815263ffffffff9091169060208101613edb8343615a7a565b63ffffffff90811682528781166020808401919091526000604080850182905260609485018890528c825261012c8352908190208551815493870151928701519587015173ffffffffffffffffffffffffffffffffffffffff166901000000000000000000027fffffff0000000000000000000000000000000000000000ffffffffffffffffff9686166501000000000002969096167fffffff000000000000000000000000000000000000000000000000ffffffffff93909516610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000090941660ff9091161792909217169190911791909117815560809091015160019091015533877fae95b2503575f3fe1b46b9e02c8ea724f2aa9340a4b06018ce7945d365eec81161400c8443615a7a565b89898760405161401f9493929190615d36565b60405180910390a350505050505050565b600082815260656020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610deb57614070816141c9565b61407b8360206141e8565b60405160200161408c929190615d6b565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527f08c379a0000000000000000000000000000000000000000000000000000000008252610fe891600401615e1b565b73ffffffffffffffffffffffffffffffffffffffff81163b614138576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fe890615e86565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6141a783614402565b6000825111806141b45750805b15610f61576141c3838361444f565b50505050565b6060610ce573ffffffffffffffffffffffffffffffffffffffff831660145b606060006141f7836002615e96565b614202906002615ac9565b67ffffffffffffffff81111561421a5761421a61485e565b6040519080825280601f01601f191660200182016040528015614244576020820181803683370190505b5090507f30000000000000000000000000000000000000000000000000000000000000008160008151811061427b5761427b6154b1565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f7800000000000000000000000000000000000000000000000000000000000000816001815181106142de576142de6154b1565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600061431a846002615e96565b614325906001615ac9565b90505b60018111156143c2577f303132333435363738396162636465660000000000000000000000000000000085600f1660108110614366576143666154b1565b1a60f81b82828151811061437c5761437c6154b1565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c936143bb81615eae565b9050614328565b5083156143fb576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fe890615f15565b9392505050565b61440b816140ea565b60405173ffffffffffffffffffffffffffffffffffffffff8216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b606073ffffffffffffffffffffffffffffffffffffffff83163b61449f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fe890615f7f565b6000808473ffffffffffffffffffffffffffffffffffffffff16846040516144c79190615f8f565b600060405180830381855af49150503d8060008114614502576040519150601f19603f3d011682016040523d82523d6000602084013e614507565b606091505b509150915061452f8282604051806060016040528060278152602001615f9c60279139614538565b95945050505050565b606083156145475750816143fb565b6143fb838381511561455c5781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fe89190615e1b565b805b811461115157600080fd5b8035610ce581614590565b600073ffffffffffffffffffffffffffffffffffffffff8216610ce5565b614592816145a8565b8035610ce5816145c6565b600080604083850312156145f0576145f0600080fd5b60006145fc858561459d565b925050602061460d858286016145cf565b9150509250929050565b7fffffffff000000000000000000000000000000000000000000000000000000008116614592565b8035610ce581614617565b60006020828403121561465f5761465f600080fd5b600061344c848461463f565b8015155b82525050565b60208101610ce5828461466b565b60008060006060848603121561469b5761469b600080fd5b60006146a7868661459d565b93505060206146b8868287016145cf565b92505060406146c98682870161459d565b9150509250925092565b6000602082840312156146e8576146e8600080fd5b600061344c848461459d565b61466f816145a8565b60208101610ce582846146f4565b8061466f565b60208101610ce5828461470b565b60006020828403121561473457614734600080fd5b600061344c84846145cf565b60008060006060848603121561475857614758600080fd5b6000614764868661459d565b9350506020614775868287016145cf565b92505060406146c9868287016145cf565b63ffffffff8116614592565b8035610ce581614786565b6000602082840312156147b2576147b2600080fd5b600061344c8484614792565b67ffffffffffffffff8116614592565b8035610ce5816147be565b6000602082840312156147ee576147ee600080fd5b600061344c84846147ce565b6000806000806080858703121561481357614813600080fd5b600061481f878761459d565b9450506020614830878288016147ce565b935050604061484187828801614792565b92505060606148528782880161459d565b91505092959194509250565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f830116810181811067ffffffffffffffff821117156148d1576148d161485e565b6040525050565b60006148e360405190565b90506148ef828261488d565b919050565b600067ffffffffffffffff82111561490e5761490e61485e565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011660200192915050565b82818337506000910152565b600061495c614957846148f4565b6148d8565b90508281526020810184848401111561497757614977600080fd5b61498284828561493d565b509392505050565b600082601f83011261499e5761499e600080fd5b813561344c848260208601614949565b600080604083850312156149c4576149c4600080fd5b60006149d085856145cf565b925050602083013567ffffffffffffffff8111156149f0576149f0600080fd5b61460d8582860161498a565b600060608284031215614a1157614a11600080fd5b50919050565b60008083601f840112614a2c57614a2c600080fd5b50813567ffffffffffffffff811115614a4757614a47600080fd5b602083019150836020820283011115614a6257614a62600080fd5b9250929050565b60008083601f840112614a7e57614a7e600080fd5b50813567ffffffffffffffff811115614a9957614a99600080fd5b602083019150836001820283011115614a6257614a62600080fd5b600060408284031215614a1157614a11600080fd5b600080600080600080600060a0888a031215614ae757614ae7600080fd5b873567ffffffffffffffff811115614b0157614b01600080fd5b614b0d8a828b016149fc565b975050602088013567ffffffffffffffff811115614b2d57614b2d600080fd5b614b398a828b01614a17565b9650965050604088013567ffffffffffffffff811115614b5b57614b5b600080fd5b614b678a828b01614a69565b9450945050606088013567ffffffffffffffff811115614b8957614b89600080fd5b614b958a828b01614ab4565b9250506080614ba68a828b0161459d565b91505092959891949750929550565b63ffffffff811661466f565b60208101610ce58284614bb5565b60006101808284031215614a1157614a11600080fd5b600060208284031215614bfa57614bfa600080fd5b813567ffffffffffffffff811115614c1457614c14600080fd5b61344c84828501614bcf565b600060a08284031215614a1157614a11600080fd5b60008060c08385031215614c4b57614c4b600080fd5b6000614c578585614c20565b92505060a061460d8582860161459d565b60ff811661466f565b60a08101614c7f8288614c68565b614c8c6020830187614bb5565b614c996040830186614bb5565b614ca660608301856146f4565b614cb3608083018461470b565b9695505050505050565b6000806000806000806000610120888a031215614cdc57614cdc600080fd5b873567ffffffffffffffff811115614cf657614cf6600080fd5b614d028a828b016149fc565b975050602088013567ffffffffffffffff811115614d2257614d22600080fd5b614d2e8a828b01614a17565b9650965050604088013567ffffffffffffffff811115614d5057614d50600080fd5b614d5c8a828b01614a69565b9450945050606088013567ffffffffffffffff811115614d7e57614d7e600080fd5b614d8a8a828b01614ab4565b9250506080614ba68a828b01614c20565b600060a08284031215614db057614db0600080fd5b600061344c8484614c20565b6000806000806000806101008789031215614dd957614dd9600080fd5b6000614de5898961459d565b9650506020614df689828a0161459d565b955050604087013567ffffffffffffffff811115614e1657614e16600080fd5b614e2289828a01614ab4565b9450506060614e3389828a016149fc565b93505060c0614e4489828a0161459d565b92505060e0614e5589828a016145cf565b9150509295509295509295565b67ffffffffffffffff811661466f565b60208101610ce58284614e62565b600060808284031215614a1157614a11600080fd5b60008060008060008060008060006101408a8c031215614eb757614eb7600080fd5b6000614ec38c8c6147ce565b9950506020614ed48c828d0161459d565b98505060408a013567ffffffffffffffff811115614ef457614ef4600080fd5b614f008c828d01614e80565b97505060608a013567ffffffffffffffff811115614f2057614f20600080fd5b614f2c8c828d01614ab4565b9650506080614f3d8c828d016149fc565b95505060e0614f4e8c828d0161459d565b945050610100614f608c828d016145cf565b9350506101208a013567ffffffffffffffff811115614f8157614f81600080fd5b614f8d8c828d01614a69565b92509250509295985092959850929598565b6000610ce5826145a8565b6000610ce582614f9f565b61466f81614faa565b60408101614fcc828561470b565b6143fb6020830184614fb5565b60408101614fe782856146f4565b6143fb602083018461470b565b6040810161500282856146f4565b6143fb60208301846146f4565b602f81526000602082017f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636581527f20726f6c657320666f722073656c660000000000000000000000000000000000602082015291505b5060400190565b60208082528101610ce58161500f565b602c81526000602082017f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682081527f64656c656761746563616c6c000000000000000000000000000000000000000060208201529150615065565b60208082528101610ce58161507c565b602c81526000602082017f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682081527f6163746976652070726f7879000000000000000000000000000000000000000060208201529150615065565b60208082528101610ce5816150e6565b6060810161515e8286614e62565b61516b6020830185614bb5565b61344c604083018461470b565b603881526000602082017f555550535570677261646561626c653a206d757374206e6f742062652063616c81527f6c6564207468726f7567682064656c656761746563616c6c000000000000000060208201529150615065565b60208082528101610ce581615178565b82818337505050565b6000835b93507f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83111561522157615221600080fd5b6020830292506152328385846151e2565b50500190565b600061344c8284866151eb565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe13685900301811261527e5761527e600080fd5b80840192508235915067ffffffffffffffff82111561529f5761529f600080fd5b6020830192506001820236038313156152ba576152ba600080fd5b509250929050565b6000610ce58260601b90565b6000610ce5826152c2565b61466f6152e5826145a8565b6152ce565b600061523283858461493d565b600061530382866152d9565b60148201915061452f8284866152ea565b8183526000602084016151ef565b818352600060208401935061533883858461493d565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401165b9093019392505050565b60c08101615377828b614e62565b615384602083018a6146f4565b615391604083018961470b565b61539e606083018861470b565b81810360808301526153b1818688615314565b905081810360a08301526153c6818486615322565b9a9950505050505050505050565b602e81526000602082017f496e697469616c697a61626c653a20636f6e747261637420697320616c72656181527f647920696e697469616c697a656400000000000000000000000000000000000060208201529150615065565b60208082528101610ce5816153d4565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe13685900301811261547757615477600080fd5b80840192508235915067ffffffffffffffff82111561549857615498600080fd5b602092830192820236038313156152ba576152ba600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060ff8216610ce5565b61466f816154e0565b60208101610ce582846154eb565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff8216915063ffffffff8316925081830263ffffffff81165b915080821461556157615561615502565b5092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b63ffffffff91821691166000826155b0576155b0615568565b500490565b81810381811115610ce557610ce5615502565b604081016155d682856146f4565b6143fb602083018461466b565b60a081016155f1828961470b565b6155fe602083018861470b565b61560b60408301876146f4565b61561860608301866146f4565b818103608083015261562b818486615322565b98975050505050505050565b8051610ce5816147be565b60006020828403121561565757615657600080fd5b600061344c8484615637565b60ff8116614592565b8035610ce581615663565b60006020828403121561568c5761568c600080fd5b600061344c848461566c565b61ffff8116614592565b8035610ce581615698565b6000602082840312156156c2576156c2600080fd5b600061344c84846156a2565b6000610ce58260f81b90565b61466f60ff82166156ce565b6000610ce58260c01b90565b61466f67ffffffffffffffff82166156e6565b6000610ce58260f01b90565b61466f61ffff8216615705565b600061572a82886156da565b60018201915061573a82876156f2565b60088201915061574a828661470b565b60208201915061575a82856156da565b60018201915061576a8284615711565b5060020195945050505050565b600061578382886156da565b6001820191506157938287615711565b6002820191506157a382866156da565b6001820191506157b48284866151eb565b979650505050505050565b60005b838110156157da5781810151838201526020016157c2565b50506000910152565b60006157ed825190565b6157fb8185602086016157bf565b9290920192915050565b6000610ce58260e01b90565b61466f63ffffffff8216615805565b600061582c828a6156da565b60018201915061583c82896156f2565b60088201915061584c828861470b565b60208201915061585c82876157e3565b91506158688286615811565b6004820191506158798284866152ea565b9998505050505050505050565b60808101615894828861470b565b6158a160208301876146f4565b6158ae60408301866146f4565b81810360608301526157b4818486615322565b601d81526000602082017f416464726573733a20696e73756666696369656e742062616c616e6365000000815291505b5060200190565b60208082528101610ce5816158c1565b600081610ce5565b603a81526000602082017f416464726573733a20756e61626c6520746f2073656e642076616c75652c207281527f6563697069656e74206d6179206861766520726576657274656400000000000060208201529150615065565b60208082528101610ce581615910565b8051610ce581614590565b60006020828403121561599a5761599a600080fd5b600061344c848461597a565b602e81526000602082017f45524331393637557067726164653a206e657720696d706c656d656e7461746981527f6f6e206973206e6f74205555505300000000000000000000000000000000000060208201529150615065565b60208082528101610ce5816159a6565b602981526000602082017f45524331393637557067726164653a20756e737570706f727465642070726f7881527f6961626c6555554944000000000000000000000000000000000000000000000060208201529150615065565b60208082528101610ce581615a10565b63ffffffff918216919081169082820190811115610ce557610ce5615502565b600067ffffffffffffffff8216915067ffffffffffffffff8316925081830267ffffffffffffffff8116615550565b80820180821115610ce557610ce5615502565b60008085851115615aef57615aef600080fd5b83861115615aff57615aff600080fd5b5050820193919092039150565b803582826020821015615b4d57615b487fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff836020036008021b90565b831692505b505092915050565b60006143fb6020840184614792565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe136859003018112615b9d57615b9d600080fd5b83810160208101935035915067ffffffffffffffff821115615bc157615bc1600080fd5b6020820236038313156152ba576152ba600080fd5b600060608301615be68380615b55565b615bf08582614bb5565b50615bfe6020840184615b64565b8583036020870152615c11838284615314565b92505050615c226040840184615b64565b8583036040870152614cb3838284615314565b60408101615c43828561470b565b818103602083015261344c8184615bd6565b600061344c8284866152ea565b6000615c6e82896156f2565b600882019150615c7e82886152d9565b601482019150615c8e828761470b565b602082019150615c9e828661470b565b602082019150615cae828561470b565b602082019150615cbe82846152d9565b506014019695505050505050565b602b81526000602082017f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206981527f6e697469616c697a696e6700000000000000000000000000000000000000000060208201529150615065565b60208082528101610ce581615ccc565b60808101615d448287614bb5565b615d516020830186614e62565b615d5e6040830185614bb5565b61452f606083018461470b565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081526017016000615d9d82856157e3565b7f206973206d697373696e6720726f6c65200000000000000000000000000000008152601101915061344c82846157e3565b6000615dd9825190565b808452602084019350615df08185602086016157bf565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f82011661535f565b602080825281016143fb8184615dcf565b602d81526000602082017f455243313936373a206e657720696d706c656d656e746174696f6e206973206e81527f6f74206120636f6e74726163740000000000000000000000000000000000000060208201529150615065565b60208082528101610ce581615e2c565b81810280821583820485141761556157615561615502565b600081615ebd57615ebd615502565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b60208082527f537472696e67733a20686578206c656e67746820696e73756666696369656e74910190815260006158f1565b60208082528101610ce581615ee3565b602681526000602082017f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f81527f6e7472616374000000000000000000000000000000000000000000000000000060208201529150615065565b60208082528101610ce581615f25565b60006143fb82846157e356fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212202c9073bda4a8585e646877704375504d9b77be228f1b35d596bb70aab9a8007164736f6c63430008130033

Deployed Bytecode

0x60806040526004361061033e5760003560e01c8063639a6c2b116101b0578063c4bf9ea4116100ec578063debebe0411610095578063f288a2e21161006f578063f288a2e214610a9c578063f340fa0114610ad0578063f5ac134d14610ae3578063fb035bc314610b0d57600080fd5b8063debebe0414610a47578063e3613d7314610a5a578063ed2d9ba014610a8957600080fd5b8063d547741f116100c6578063d547741f146109d3578063d77de079146109f3578063dc9a4ef614610a1357600080fd5b8063c4bf9ea41461095f578063c608b5e81461097f578063c70cb102146109b357600080fd5b806380b79a671161015957806399464c891161013357806399464c891461088b578063a217fddf146108a0578063ab9c67ad146108b5578063b16033911461093f57600080fd5b806380b79a67146107f857806391d148541461081857806396698cc51461086b57600080fd5b8063736f16181161018a578063736f1618146107965780637393da9e146107b657806379ce0468146107cd57600080fd5b8063639a6c2b1461074157806366c5c4a0146107615780636ee9a0d51461077657600080fd5b80632aae79331161027f5780633e48a08711610228578063469b236211610202578063469b2362146106d85780634a253074146107065780634f1ef2861461071957806352d1902d1461072c57600080fd5b80633e48a0871461067857806341ae4059146106985780634415fe46146106b857600080fd5b80633237c2fd116102595780633237c2fd1461061857806336568abe146106385780633659cfe61461065857600080fd5b80632aae7933146105a45780632b7d2bad146105c45780632f2ff15d146105f857600080fd5b80630c2d17bb116102ec57806324ea54f4116102c657806324ea54f4146104e057806327e235e31461051457806328e80f47146105425780632a80f0f21461058457600080fd5b80630c2d17bb1461044857806318bdffbb14610468578063248a9ca3146104a357600080fd5b806304d295a21161031d57806304d295a2146103dd578063054f7d9c146103fd57806306fb89fa1461041757600080fd5b8062f714ce1461034357806301ffc9a714610365578063028ad6e11461039b575b600080fd5b34801561034f57600080fd5b5061036361035e3660046145da565b610b33565b005b34801561037157600080fd5b5061038561038036600461464a565b610c8f565b6040516103929190614675565b60405180910390f35b3480156103a757600080fd5b506103856103b6366004614683565b61012760209081526000938452604080852082529284528284209052825290205460ff1681565b3480156103e957600080fd5b506103636103f8366004614683565b610ceb565b34801561040957600080fd5b506097546103859060ff1681565b34801561042357600080fd5b506103856104323660046146d3565b6101266020526000908152604090205460ff1681565b34801561045457600080fd5b506103636104633660046146d3565b610db8565b34801561047457600080fd5b50610125546104969073ffffffffffffffffffffffffffffffffffffffff1681565b60405161039291906146fd565b3480156104af57600080fd5b506104d36104be3660046146d3565b60009081526065602052604090206001015490565b6040516103929190614711565b3480156104ec57600080fd5b506104d37f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a504181565b34801561052057600080fd5b506104d361052f36600461471f565b61012d6020526000908152604090205481565b34801561054e57600080fd5b5061038561055d366004614740565b61012860209081526000938452604080852082529284528284209052825290205460ff1681565b34801561059057600080fd5b5061036361059f366004614740565b610def565b3480156105b057600080fd5b506103636105bf3660046146d3565b610eb2565b3480156105d057600080fd5b506104d37f542178611b653a605b79640db9b52a7afa591d6ace75cd36686e0ee264f4f57281565b34801561060457600080fd5b506103636106133660046145da565b610f3c565b34801561062457600080fd5b5061036361063336600461471f565b610f66565b34801561064457600080fd5b506103636106533660046145da565b610f99565b34801561066457600080fd5b5061036361067336600461471f565b610ffb565b34801561068457600080fd5b5061036361069336600461479d565b611154565b3480156106a457600080fd5b506103636106b3366004614683565b611187565b3480156106c457600080fd5b506103636106d33660046147d9565b611243565b3480156106e457600080fd5b50610124546104969073ffffffffffffffffffffffffffffffffffffffff1681565b6103636107143660046147fa565b611276565b6103636107273660046149ae565b611413565b34801561073857600080fd5b506104d3611559565b34801561074d57600080fd5b5061036361075c366004614740565b6115ef565b34801561076d57600080fd5b506103636116af565b34801561078257600080fd5b50610363610791366004614ac9565b61172d565b3480156107a257600080fd5b506103636107b136600461471f565b6119fd565b3480156107c257600080fd5b506104d361012a5481565b3480156107d957600080fd5b50610129546107eb9063ffffffff1681565b6040516103929190614bc1565b34801561080457600080fd5b50610363610813366004614be5565b611a30565b34801561082457600080fd5b506103856108333660046145da565b600091825260656020908152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b34801561087757600080fd5b50610363610886366004614c35565b611f4f565b34801561089757600080fd5b50610363612150565b3480156108ac57600080fd5b506104d3600081565b3480156108c157600080fd5b5061092e6108d03660046146d3565b61012c602052600090815260409020805460019091015460ff82169163ffffffff61010082048116926501000000000083049091169173ffffffffffffffffffffffffffffffffffffffff6901000000000000000000909104169085565b604051610392959493929190614c71565b34801561094b57600080fd5b5061036361095a3660046146d3565b6121d1565b34801561096b57600080fd5b5061036361097a366004614cbd565b612204565b34801561098b57600080fd5b506104d37ff4e710c64967f31ba1090db2a7dd9e704155d00947ce853da47446cb68ee65da81565b3480156109bf57600080fd5b506103636109ce366004614d9b565b6125bc565b3480156109df57600080fd5b506103636109ee3660046145da565b61277b565b3480156109ff57600080fd5b50610363610a0e36600461479d565b6127a0565b348015610a1f57600080fd5b506104d37f60044782a422109ac08a415e44260ad5d3bad63d96ebe1fac0363399642ee3f281565b6104d3610a55366004614dbc565b6127d3565b348015610a6657600080fd5b5061012b54610a7c9067ffffffffffffffff1681565b6040516103929190614e72565b6104d3610a97366004614e95565b6128dc565b348015610aa857600080fd5b506104d37ff66846415d2bf9eabda9e84793ff9c0ea96d87f50fc41e66aa16469c6a442f0581565b610363610ade36600461471f565b612c06565b348015610aef57600080fd5b5061012b546107eb9068010000000000000000900463ffffffff1681565b348015610b1957600080fd5b50610129546107eb90640100000000900463ffffffff1681565b73ffffffffffffffffffffffffffffffffffffffff8116610b80576040517f2f8a6f2200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600090815261012d6020526040902054821115610bca576040517ff7a7a59500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81600003610c04576040517fccb1e81400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600090815261012d6020526040902080548390039055610c3b73ffffffffffffffffffffffffffffffffffffffff821683612c9f565b3373ffffffffffffffffffffffffffffffffffffffff167f56c54ba9bd38d8fd62012e42c7ee564519b09763c426d331b3661b537ead19b28383604051610c83929190614fbe565b60405180910390a25050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7132f8a9000000000000000000000000000000000000000000000000000000001480610ce55750610ce582612d7c565b92915050565b7ff66846415d2bf9eabda9e84793ff9c0ea96d87f50fc41e66aa16469c6a442f05610d1581612e13565b60008481526101276020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845282528083208584529091529081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555184907f2985d9844f1c5cfc77069b4f176964ff8687324b391d3b394a164024d602135d90610daa9086908690614fd9565b60405180910390a250505050565b7ff66846415d2bf9eabda9e84793ff9c0ea96d87f50fc41e66aa16469c6a442f05610de281612e13565b610deb82612e1d565b5050565b7ff66846415d2bf9eabda9e84793ff9c0ea96d87f50fc41e66aa16469c6a442f05610e1981612e13565b60008481526101286020908152604080832073ffffffffffffffffffffffffffffffffffffffff808816855290835281842090861684529091529081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555184907fa9611403ffbf5e30519e911927c5f3566e7661a8f9640ffefd7fde30b7319d0690610daa9086908690614ff4565b7ff66846415d2bf9eabda9e84793ff9c0ea96d87f50fc41e66aa16469c6a442f05610edc81612e13565b6000828152610126602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555183917fb878feae2e86bc3890d16dda54077e7ef0e0ffbacd789b2c258b92493e7d28d591a25050565b600082815260656020526040902060010154610f5781612e13565b610f618383612e7f565b505050565b7ff66846415d2bf9eabda9e84793ff9c0ea96d87f50fc41e66aa16469c6a442f05610f9081612e13565b610deb82612f73565b73ffffffffffffffffffffffffffffffffffffffff81163314610ff1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fe89061506c565b60405180910390fd5b610deb828261303c565b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000ffbbdad0241d5eb38cce77c4e21322b42b2d921216300361106a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fe8906150d6565b7f000000000000000000000000ffbbdad0241d5eb38cce77c4e21322b42b2d921273ffffffffffffffffffffffffffffffffffffffff166110df7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff161461112c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fe890615140565b611135816130f7565b6040805160008082526020820190925261115191839190613121565b50565b7ff66846415d2bf9eabda9e84793ff9c0ea96d87f50fc41e66aa16469c6a442f0561117e81612e13565b610deb82613274565b7ff66846415d2bf9eabda9e84793ff9c0ea96d87f50fc41e66aa16469c6a442f056111b181612e13565b60008481526101276020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845282528083208584529091529081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555184907f9034eb299f78da99651eea0f72d646742962b9d29fe8fbbf25ab0de0fd9a678e90610daa9086908690614fd9565b7ff66846415d2bf9eabda9e84793ff9c0ea96d87f50fc41e66aa16469c6a442f0561126d81612e13565b610deb8261331f565b61127e6133c8565b600084815261012c60205260409020805460ff166001146112cb576040517f3d1c563c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61012b5467ffffffffffffffff9081169085161015611316576040517f25a8b6d700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600181015461012a548084111561132a5750825b6000611337878784613407565b9050828111611372576040517f9eca72e200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b828103348111156113af576040517f356680b700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b818560010181905550887f25ffed1d7b3823d2e30120aec66c9ccaad42f93ab6d1537ba9d785a2e446f4d08989896040516113ec93929190615150565b60405180910390a2803411156114085761140833823403613454565b505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000ffbbdad0241d5eb38cce77c4e21322b42b2d9212163003611482576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fe8906150d6565b7f000000000000000000000000ffbbdad0241d5eb38cce77c4e21322b42b2d921273ffffffffffffffffffffffffffffffffffffffff166114f77f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614611544576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fe890615140565b61154d826130f7565b610deb82826001613121565b60003073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000ffbbdad0241d5eb38cce77c4e21322b42b2d921216146115ca576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fe8906151d2565b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc90565b7ff66846415d2bf9eabda9e84793ff9c0ea96d87f50fc41e66aa16469c6a442f0561161981612e13565b60008481526101286020908152604080832073ffffffffffffffffffffffffffffffffffffffff808816855290835281842090861684529091529081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555184907f8486629005b3a257ef75d8acf26fdbc2127e21a2b2fe401e18e938e76d02fc0690610daa9086908690614ff4565b7ff4e710c64967f31ba1090db2a7dd9e704155d00947ce853da47446cb68ee65da6116d981612e13565b609780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556040517fe6fdbf73945dd61794a752b9181ea29f77170a7b1ffd37e0a7ff9d2c6f7258b990600090a150565b6117356133c8565b600061177888868661174a602088018861471f565b8b8b60405160200161175d929190615238565b604051602081830303815290604052805190602001206134f3565b6020808201519192506000916117d2916117949087018761471f565b6117a16020880188615245565b6040516020016117b3939291906152f7565b6040516020818303038152906040528051906020012085600033613a34565b600081815261012c6020526040902080549192509060ff1615611821576040517fab70a5d400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606083015173ffffffffffffffffffffffffffffffffffffffff163314611874576040517f73c3cc3a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660021781556000806118ad602088018861471f565b73ffffffffffffffffffffffffffffffffffffffff16146119b857835160408501516000917f8193399c00000000000000000000000000000000000000000000000000000000913390878f8f61190660208f018f615245565b60405160240161191d989796959493929190615369565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925291506119b4906119ad9089018961471f565b5a83613a91565b9150505b827fee6b24cc42698e8355f8a268e7237b2db8c755fe5ecc21e9ffe4e667b5825d94826040516119e89190614675565b60405180910390a25050505050505050505050565b7ff66846415d2bf9eabda9e84793ff9c0ea96d87f50fc41e66aa16469c6a442f05611a2781612e13565b610deb82613aa9565b600054610100900460ff1615808015611a505750600054600160ff909116105b80611a6a5750303b158015611a6a575060005460ff166001145b611aa0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fe89061542e565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558015611afe57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b611b06613b67565b611b0e613ba8565b6000611b226101408401610120850161471f565b73ffffffffffffffffffffffffffffffffffffffff1603611b6f576040517fd5ae8cf700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611b836101608401610140850161471f565b73ffffffffffffffffffffffffffffffffffffffff1603611bd0576040517f40c2354200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611be46101808401610160850161471f565b73ffffffffffffffffffffffffffffffffffffffff1603611c31576040517f6d92bcf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611c46611c41602084018461471f565b612f73565b611c5e611c59604084016020850161471f565b613aa9565b60005b611c6e606084018461543e565b9050811015611cab57611ca3611c87606085018561543e565b83818110611c9757611c976154b1565b90506020020135612e1d565b600101611c61565b50611cbe6101208301610100840161479d565b61012b805463ffffffff9290921668010000000000000000027fffffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffff909216919091179055611d19611d1460a084016080850161479d565b613c13565b611d31611d2c60c0840160a0850161479d565b613274565b611d3e8260c00135613cc7565b611d57611d52610100840160e085016147d9565b61331f565b611d736000611d6e6101408501610120860161471f565b612e7f565b611da97ff66846415d2bf9eabda9e84793ff9c0ea96d87f50fc41e66aa16469c6a442f05611d6e6101408501610120860161471f565b611ddf7f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a5041611d6e6101608501610140860161471f565b611e157ff4e710c64967f31ba1090db2a7dd9e704155d00947ce853da47446cb68ee65da611d6e6101808501610160860161471f565b6000805b611e26604085018561543e565b9050811015611ee257611e3c604085018561543e565b82818110611e4c57611e4c6154b1565b9050602002016020810190611e61919061471f565b915073ffffffffffffffffffffffffffffffffffffffff8216611eb0576040517ffbc5fc2f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611eda7f60044782a422109ac08a415e44260ad5d3bad63d96ebe1fac0363399642ee3f283612e7f565b600101611e19565b50508015610deb57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1690556040517f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890611f43906001906154f4565b60405180910390a15050565b611f576133c8565b6000611f6960a084016080850161471f565b90506000611f9260408501356060860135602087018035908690611f8d908a61471f565b613a34565b600081815261012c6020526040902080549192509060ff16600214611fe3576040517f14532a0c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600181015480851115612022576040517f1d8b710000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81546901000000000000000000900473ffffffffffffffffffffffffffffffffffffffff16338114612080576040517f55d9010000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600317835573ffffffffffffffffffffffffffffffffffffffff808216600081815261012d6020908152604080832080548c019055938916825292902080548986030190559085906120f8908a018a61471f565b73ffffffffffffffffffffffffffffffffffffffff167f498fc64c3c7f25c2a420d7cbf8f6e5e9f63b033b11a621d30e4a9119587ede65888a60405161213f929190614fd9565b60405180910390a450505050505050565b7f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a504161217a81612e13565b609780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556040517f61340a1b154d5d21d259a74bf95379201799b9d12cc6509bb46cb56dc281df5590600090a150565b7ff66846415d2bf9eabda9e84793ff9c0ea96d87f50fc41e66aa16469c6a442f056121fb81612e13565b610deb82613cc7565b61220c6133c8565b600061222188868661174a602088018861471f565b9050600061225460408401356060850135602086013561224760a088016080890161471f565b611f8d602089018961471f565b9050612263602085018561471f565b6122706020860186615245565b604051602001612282939291906152f7565b604051602081830303815290604052805190602001208360600135146122d4576040517f521bdd1100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160200151836040013514612315576040517faed145d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600081815261012c60205260409020805460ff16600114612362576040517ff8c22cf100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606083015181547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0073ffffffffffffffffffffffffffffffffffffffff909216690100000000000000000002919091167fffffff0000000000000000000000000000000000000000ffffffffffffffff009091161760021781556000806123ec602088018861471f565b73ffffffffffffffffffffffffffffffffffffffff16146125865783516000907fdc5cd53c000000000000000000000000000000000000000000000000000000009061243b602089018961471f565b6040880151878f8f61245060208f018f615245565b604051602401612467989796959493929190615369565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092528454909250603f916125069163ffffffff650100000000009091041690615531565b6125109190615597565b63ffffffff1661012c5a61252491906155b5565b1161255b576040517f657989e900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61258261256b602089018961471f565b845465010000000000900463ffffffff1683613a91565b9150505b827ff5abe1a043591aece5d845c5d02d67e11824a16bfdb48b9d7934486e3bef95a98560600151836040516119e89291906155c8565b6125c46133c8565b60006125d660a083016080840161471f565b905060006125fa60408401356060850135602086018035908690611f8d908961471f565b90503373ffffffffffffffffffffffffffffffffffffffff83161461264b576040517f6464486800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600081815261012c60205260409020805460ff16600114612698576040517f5f158cf700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8054610100900463ffffffff1643116126dd576040517f6d542c0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018082015473ffffffffffffffffffffffffffffffffffffffff8516600081815261012d60209081526040808320805490950190945586825261012c905282812080547fffffff00000000000000000000000000000000000000000000000000000000001681559093018390559051909184917f800e41f8023d1b860a629dfe2b3fc12d34767238ec1b02f5f7e8a3475b9dadf69190a350505050565b60008281526065602052604090206001015461279681612e13565b610f61838361303c565b7ff66846415d2bf9eabda9e84793ff9c0ea96d87f50fc41e66aa16469c6a442f056127ca81612e13565b610deb82613c13565b60006127dd6133c8565b73ffffffffffffffffffffffffffffffffffffffff82166127fc573391505b61284a8761280d602088018861471f565b61281a6020890189615245565b60405160200161282c939291906152f7565b60405160208183030381529060405280519060200120858533613a34565b90506128778161285d60208701876147d9565b61286d604088016020890161479d565b8760400135613d3e565b8087337ff3a2958f23705cbc6bbc0922c0af3c82b76d93e8acc5c17ef86736cf4563fb85868a876128ab60208d018d61471f565b6128b860208e018e615245565b6040516128ca969594939291906155e3565b60405180910390a49695505050505050565b60006128e66133c8565b61012460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663fe428ed36040518163ffffffff1660e01b8152600401602060405180830381865afa158015612954573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129789190615642565b67ffffffffffffffff168a67ffffffffffffffff16146129c4576040517f0db21db600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff84166129e3573393505b60006129f260208a018a615677565b60ff16600003612a4e5760028b8b612a0d60208d018d615677565b612a1d60408e0160208f016156ad565b604051602001612a3195949392919061571e565b604051602081830303815290604052805190602001209050612b21565b6000612a5d60208b018b615677565b612a6d60408c0160208d016156ad565b612a7a60408d018d61543e565b9050612a8960408e018e61543e565b604051602001612a9d959493929190615777565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052905060028c8c83612adf60608f018f615245565b90508e8060600190612af19190615245565b604051602001612b079796959493929190615820565b604051602081830303815290604052805190602001209150505b612b6f81612b3260208b018b61471f565b612b3f60208c018c615245565b604051602001612b51939291906152f7565b60405160208183030381529060405280519060200120888833613a34565b9150612b9c82612b8260208a018a6147d9565b612b9260408b0160208c0161479d565b8a60400135613d3e565b8181337fb72b05c090ac4ae9ec18b7e708d597093716f98567026726f6f5d9f1723161788989612bcf60208f018f61471f565b8e8060200190612bdf9190615245565b604051612bf0959493929190615886565b60405180910390a4509998505050505050505050565b612c0e6133c8565b73ffffffffffffffffffffffffffffffffffffffff8116612c5b576040517f3422bc3900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b34600003612c95576040517f0ddbd93400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6111518134613454565b80471015612cd9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fe8906158f8565b60008273ffffffffffffffffffffffffffffffffffffffff1682604051612cff90615908565b60006040518083038185875af1925050503d8060008114612d3c576040519150601f19603f3d011682016040523d82523d6000602084013e612d41565b606091505b5050905080610f61576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fe89061596a565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610ce557507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610ce5565b6111518133614030565b6000818152610126602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555182917fcf6ab1ad888a23cab770a17862e882b2a503fecaa716a2c147d43692db6762d991a250565b600082815260656020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610deb57600082815260656020908152604080832073ffffffffffffffffffffffffffffffffffffffff85168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055612f153390565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b73ffffffffffffffffffffffffffffffffffffffff8116612fc0576040517ff270e94a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61012480547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83161790556040517f75bcc4f3a8eeec60c22df746d7f53083c892df4b1e07b2be152f117df8f353f7906130319083906146fd565b60405180910390a150565b600082815260656020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff1615610deb57600082815260656020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b7ff66846415d2bf9eabda9e84793ff9c0ea96d87f50fc41e66aa16469c6a442f05610deb81612e13565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff161561315457610f61836140ea565b8273ffffffffffffffffffffffffffffffffffffffff166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156131d9575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682019092526131d691810190615985565b60015b61320f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fe890615a00565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8114613268576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fe890615a6a565b50610f6183838361419e565b620927c063ffffffff821611156132b7576040517f916551ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61012980547fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff1664010000000063ffffffff8416021790556040517fd2d353df76578044ea52bec30dc61526b5546fb34503457fa20b79e4fdcde32e90613031908390614bc1565b8067ffffffffffffffff16600003613363576040517f20a88e0100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61012b80547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff83161790556040517f2c69ced866ae8fc3b771915857e877d4bf0153be881ca6b53b004c47db57131c90613031908390614e72565b60975460ff1615613405576040517f379dfc6300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b61012954600090829061342890640100000000900463ffffffff1685615a7a565b6134389063ffffffff1686615a9a565b67ffffffffffffffff1661344c9190615ac9565b949350505050565b68056bc75e2d63100000811115613497576040517fc56d46d300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216600081815261012d602052604090819020805484019055517fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c90610c83908490614711565b6040805160808101825260008082526020820181905291810182905260608101919091526135276101a06101808688615adc565b61353091615b0c565b67ffffffffffffffff168152600061354e6101e06101c08789615adc565b61355791615b0c565b60806135696101c06101a0898b615adc565b61357291615b0c565b901b1790506135876102206102008789615adc565b61359091615b0c565b60806135a26102006101e0898b615adc565b6135ab91615b0c565b901b1760208301526135c36102606102408789615adc565b6135cc91615b0c565b60806135de610240610220898b615adc565b6135e791615b0c565b901b17604083015260006136016102a0610280888a615adc565b61360a91615b0c565b608061361c6102806102608a8c615adc565b61362591615b0c565b901b179050600061363c6102c06102a0898b615adc565b61364591615b0c565b90506136576102e06102c0898b615adc565b61366091615b0c565b73ffffffffffffffffffffffffffffffffffffffff9081166060860152610124546040517fedc55b94000000000000000000000000000000000000000000000000000000008152911690819063edc55b94906136c29086908e90600401615c35565b600060405180830381600087803b1580156136dc57600080fd5b505af11580156136f0573d6000803e3d6000fd5b505050508073ffffffffffffffffffffffffffffffffffffffff1663fe428ed36040518163ffffffff1660e01b8152600401602060405180830381865afa15801561373f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137639190615642565b67ffffffffffffffff16856000015167ffffffffffffffff16146137b3576040517f0db21db600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8584146137ec576040517f921c328700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081527f16d6d09ad43c2e13327e8e85b0f16a19ef2e63b72c391bfd77d21c5d49902185602052604090205460ff16806138725750600080527f16d6d09ad43c2e13327e8e85b0f16a19ef2e63b72c391bfd77d21c5d499021856020527fdf4fae2a9d03ddefae2c9e431bd1ae49d400972b66abd41187abff73623b3c4b5460ff165b806138b757506040808601516000908152610128602090815282822073ffffffffffffffffffffffffffffffffffffffff8b16835281528282203383529052205460ff165b6138ed576040517fa822f97100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152610126602052604090205460ff168061394557506040808601516000908152610127602090815282822073ffffffffffffffffffffffffffffffffffffffff8b16835281528282208583529052205460ff165b61397b576040517febe1d07800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101255460405160009173ffffffffffffffffffffffffffffffffffffffff16906139a9908c908c90615c55565b6000604051808303816000865af19150503d80600081146139e6576040519150601f19603f3d011682016040523d82523d6000602084013e6139eb565b606091505b5050905080613a26576040517fd611c31800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505095945050505050565b6000468285888887604051602001613a5196959493929190615c62565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101209695505050505050565b600080600083516020850160008888f1949350505050565b73ffffffffffffffffffffffffffffffffffffffff8116613af6576040517f3815ff6600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61012580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83161790556040517fe6e1c2bf73bb6cc1c20546306996ac2050af3e2cfc8d64d3173c7ef0ce549519906130319083906146fd565b600054610100900460ff16613405576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fe890615d26565b600054610100900460ff16613be9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fe890615d26565b609780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b61012b5463ffffffff6801000000000000000090910481169082161115613c66576040517fb2de8d0000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61012980547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff83161790556040517f266d22101c27a330937ff06442e5289e92a84a449d22bb001c03789f7774b62890613031908390614bc1565b66b1a2bc2ec50000811115613d08576040517ff729a96300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61012a8190556040517f1a520c8da72d8b5ebd7db613f55b33d3186f12b647fe2c197cd27bb2840b277690613031908390614711565b600084815261012c602052604090205460ff1615613d88576040517fcaa9c69700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61012b5467ffffffffffffffff9081169084161015613dd3576040517f25a8b6d700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61012a5480821115613de25750805b6000613def858584613407565b9050803414613e6e573415613e0857613e083334613454565b33600090815261012d602052604090205480821115613e53576040517f0fa9f54b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600090815261012d60205260409020908290039055613eb1565b68056bc75e2d63100000341115613eb1576040517fc56d46d300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610129546040805160a081019091526001815263ffffffff9091169060208101613edb8343615a7a565b63ffffffff90811682528781166020808401919091526000604080850182905260609485018890528c825261012c8352908190208551815493870151928701519587015173ffffffffffffffffffffffffffffffffffffffff166901000000000000000000027fffffff0000000000000000000000000000000000000000ffffffffffffffffff9686166501000000000002969096167fffffff000000000000000000000000000000000000000000000000ffffffffff93909516610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000090941660ff9091161792909217169190911791909117815560809091015160019091015533877fae95b2503575f3fe1b46b9e02c8ea724f2aa9340a4b06018ce7945d365eec81161400c8443615a7a565b89898760405161401f9493929190615d36565b60405180910390a350505050505050565b600082815260656020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610deb57614070816141c9565b61407b8360206141e8565b60405160200161408c929190615d6b565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527f08c379a0000000000000000000000000000000000000000000000000000000008252610fe891600401615e1b565b73ffffffffffffffffffffffffffffffffffffffff81163b614138576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fe890615e86565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6141a783614402565b6000825111806141b45750805b15610f61576141c3838361444f565b50505050565b6060610ce573ffffffffffffffffffffffffffffffffffffffff831660145b606060006141f7836002615e96565b614202906002615ac9565b67ffffffffffffffff81111561421a5761421a61485e565b6040519080825280601f01601f191660200182016040528015614244576020820181803683370190505b5090507f30000000000000000000000000000000000000000000000000000000000000008160008151811061427b5761427b6154b1565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f7800000000000000000000000000000000000000000000000000000000000000816001815181106142de576142de6154b1565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600061431a846002615e96565b614325906001615ac9565b90505b60018111156143c2577f303132333435363738396162636465660000000000000000000000000000000085600f1660108110614366576143666154b1565b1a60f81b82828151811061437c5761437c6154b1565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c936143bb81615eae565b9050614328565b5083156143fb576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fe890615f15565b9392505050565b61440b816140ea565b60405173ffffffffffffffffffffffffffffffffffffffff8216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b606073ffffffffffffffffffffffffffffffffffffffff83163b61449f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fe890615f7f565b6000808473ffffffffffffffffffffffffffffffffffffffff16846040516144c79190615f8f565b600060405180830381855af49150503d8060008114614502576040519150601f19603f3d011682016040523d82523d6000602084013e614507565b606091505b509150915061452f8282604051806060016040528060278152602001615f9c60279139614538565b95945050505050565b606083156145475750816143fb565b6143fb838381511561455c5781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fe89190615e1b565b805b811461115157600080fd5b8035610ce581614590565b600073ffffffffffffffffffffffffffffffffffffffff8216610ce5565b614592816145a8565b8035610ce5816145c6565b600080604083850312156145f0576145f0600080fd5b60006145fc858561459d565b925050602061460d858286016145cf565b9150509250929050565b7fffffffff000000000000000000000000000000000000000000000000000000008116614592565b8035610ce581614617565b60006020828403121561465f5761465f600080fd5b600061344c848461463f565b8015155b82525050565b60208101610ce5828461466b565b60008060006060848603121561469b5761469b600080fd5b60006146a7868661459d565b93505060206146b8868287016145cf565b92505060406146c98682870161459d565b9150509250925092565b6000602082840312156146e8576146e8600080fd5b600061344c848461459d565b61466f816145a8565b60208101610ce582846146f4565b8061466f565b60208101610ce5828461470b565b60006020828403121561473457614734600080fd5b600061344c84846145cf565b60008060006060848603121561475857614758600080fd5b6000614764868661459d565b9350506020614775868287016145cf565b92505060406146c9868287016145cf565b63ffffffff8116614592565b8035610ce581614786565b6000602082840312156147b2576147b2600080fd5b600061344c8484614792565b67ffffffffffffffff8116614592565b8035610ce5816147be565b6000602082840312156147ee576147ee600080fd5b600061344c84846147ce565b6000806000806080858703121561481357614813600080fd5b600061481f878761459d565b9450506020614830878288016147ce565b935050604061484187828801614792565b92505060606148528782880161459d565b91505092959194509250565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f830116810181811067ffffffffffffffff821117156148d1576148d161485e565b6040525050565b60006148e360405190565b90506148ef828261488d565b919050565b600067ffffffffffffffff82111561490e5761490e61485e565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011660200192915050565b82818337506000910152565b600061495c614957846148f4565b6148d8565b90508281526020810184848401111561497757614977600080fd5b61498284828561493d565b509392505050565b600082601f83011261499e5761499e600080fd5b813561344c848260208601614949565b600080604083850312156149c4576149c4600080fd5b60006149d085856145cf565b925050602083013567ffffffffffffffff8111156149f0576149f0600080fd5b61460d8582860161498a565b600060608284031215614a1157614a11600080fd5b50919050565b60008083601f840112614a2c57614a2c600080fd5b50813567ffffffffffffffff811115614a4757614a47600080fd5b602083019150836020820283011115614a6257614a62600080fd5b9250929050565b60008083601f840112614a7e57614a7e600080fd5b50813567ffffffffffffffff811115614a9957614a99600080fd5b602083019150836001820283011115614a6257614a62600080fd5b600060408284031215614a1157614a11600080fd5b600080600080600080600060a0888a031215614ae757614ae7600080fd5b873567ffffffffffffffff811115614b0157614b01600080fd5b614b0d8a828b016149fc565b975050602088013567ffffffffffffffff811115614b2d57614b2d600080fd5b614b398a828b01614a17565b9650965050604088013567ffffffffffffffff811115614b5b57614b5b600080fd5b614b678a828b01614a69565b9450945050606088013567ffffffffffffffff811115614b8957614b89600080fd5b614b958a828b01614ab4565b9250506080614ba68a828b0161459d565b91505092959891949750929550565b63ffffffff811661466f565b60208101610ce58284614bb5565b60006101808284031215614a1157614a11600080fd5b600060208284031215614bfa57614bfa600080fd5b813567ffffffffffffffff811115614c1457614c14600080fd5b61344c84828501614bcf565b600060a08284031215614a1157614a11600080fd5b60008060c08385031215614c4b57614c4b600080fd5b6000614c578585614c20565b92505060a061460d8582860161459d565b60ff811661466f565b60a08101614c7f8288614c68565b614c8c6020830187614bb5565b614c996040830186614bb5565b614ca660608301856146f4565b614cb3608083018461470b565b9695505050505050565b6000806000806000806000610120888a031215614cdc57614cdc600080fd5b873567ffffffffffffffff811115614cf657614cf6600080fd5b614d028a828b016149fc565b975050602088013567ffffffffffffffff811115614d2257614d22600080fd5b614d2e8a828b01614a17565b9650965050604088013567ffffffffffffffff811115614d5057614d50600080fd5b614d5c8a828b01614a69565b9450945050606088013567ffffffffffffffff811115614d7e57614d7e600080fd5b614d8a8a828b01614ab4565b9250506080614ba68a828b01614c20565b600060a08284031215614db057614db0600080fd5b600061344c8484614c20565b6000806000806000806101008789031215614dd957614dd9600080fd5b6000614de5898961459d565b9650506020614df689828a0161459d565b955050604087013567ffffffffffffffff811115614e1657614e16600080fd5b614e2289828a01614ab4565b9450506060614e3389828a016149fc565b93505060c0614e4489828a0161459d565b92505060e0614e5589828a016145cf565b9150509295509295509295565b67ffffffffffffffff811661466f565b60208101610ce58284614e62565b600060808284031215614a1157614a11600080fd5b60008060008060008060008060006101408a8c031215614eb757614eb7600080fd5b6000614ec38c8c6147ce565b9950506020614ed48c828d0161459d565b98505060408a013567ffffffffffffffff811115614ef457614ef4600080fd5b614f008c828d01614e80565b97505060608a013567ffffffffffffffff811115614f2057614f20600080fd5b614f2c8c828d01614ab4565b9650506080614f3d8c828d016149fc565b95505060e0614f4e8c828d0161459d565b945050610100614f608c828d016145cf565b9350506101208a013567ffffffffffffffff811115614f8157614f81600080fd5b614f8d8c828d01614a69565b92509250509295985092959850929598565b6000610ce5826145a8565b6000610ce582614f9f565b61466f81614faa565b60408101614fcc828561470b565b6143fb6020830184614fb5565b60408101614fe782856146f4565b6143fb602083018461470b565b6040810161500282856146f4565b6143fb60208301846146f4565b602f81526000602082017f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636581527f20726f6c657320666f722073656c660000000000000000000000000000000000602082015291505b5060400190565b60208082528101610ce58161500f565b602c81526000602082017f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682081527f64656c656761746563616c6c000000000000000000000000000000000000000060208201529150615065565b60208082528101610ce58161507c565b602c81526000602082017f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682081527f6163746976652070726f7879000000000000000000000000000000000000000060208201529150615065565b60208082528101610ce5816150e6565b6060810161515e8286614e62565b61516b6020830185614bb5565b61344c604083018461470b565b603881526000602082017f555550535570677261646561626c653a206d757374206e6f742062652063616c81527f6c6564207468726f7567682064656c656761746563616c6c000000000000000060208201529150615065565b60208082528101610ce581615178565b82818337505050565b6000835b93507f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83111561522157615221600080fd5b6020830292506152328385846151e2565b50500190565b600061344c8284866151eb565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe13685900301811261527e5761527e600080fd5b80840192508235915067ffffffffffffffff82111561529f5761529f600080fd5b6020830192506001820236038313156152ba576152ba600080fd5b509250929050565b6000610ce58260601b90565b6000610ce5826152c2565b61466f6152e5826145a8565b6152ce565b600061523283858461493d565b600061530382866152d9565b60148201915061452f8284866152ea565b8183526000602084016151ef565b818352600060208401935061533883858461493d565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401165b9093019392505050565b60c08101615377828b614e62565b615384602083018a6146f4565b615391604083018961470b565b61539e606083018861470b565b81810360808301526153b1818688615314565b905081810360a08301526153c6818486615322565b9a9950505050505050505050565b602e81526000602082017f496e697469616c697a61626c653a20636f6e747261637420697320616c72656181527f647920696e697469616c697a656400000000000000000000000000000000000060208201529150615065565b60208082528101610ce5816153d4565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe13685900301811261547757615477600080fd5b80840192508235915067ffffffffffffffff82111561549857615498600080fd5b602092830192820236038313156152ba576152ba600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060ff8216610ce5565b61466f816154e0565b60208101610ce582846154eb565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff8216915063ffffffff8316925081830263ffffffff81165b915080821461556157615561615502565b5092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b63ffffffff91821691166000826155b0576155b0615568565b500490565b81810381811115610ce557610ce5615502565b604081016155d682856146f4565b6143fb602083018461466b565b60a081016155f1828961470b565b6155fe602083018861470b565b61560b60408301876146f4565b61561860608301866146f4565b818103608083015261562b818486615322565b98975050505050505050565b8051610ce5816147be565b60006020828403121561565757615657600080fd5b600061344c8484615637565b60ff8116614592565b8035610ce581615663565b60006020828403121561568c5761568c600080fd5b600061344c848461566c565b61ffff8116614592565b8035610ce581615698565b6000602082840312156156c2576156c2600080fd5b600061344c84846156a2565b6000610ce58260f81b90565b61466f60ff82166156ce565b6000610ce58260c01b90565b61466f67ffffffffffffffff82166156e6565b6000610ce58260f01b90565b61466f61ffff8216615705565b600061572a82886156da565b60018201915061573a82876156f2565b60088201915061574a828661470b565b60208201915061575a82856156da565b60018201915061576a8284615711565b5060020195945050505050565b600061578382886156da565b6001820191506157938287615711565b6002820191506157a382866156da565b6001820191506157b48284866151eb565b979650505050505050565b60005b838110156157da5781810151838201526020016157c2565b50506000910152565b60006157ed825190565b6157fb8185602086016157bf565b9290920192915050565b6000610ce58260e01b90565b61466f63ffffffff8216615805565b600061582c828a6156da565b60018201915061583c82896156f2565b60088201915061584c828861470b565b60208201915061585c82876157e3565b91506158688286615811565b6004820191506158798284866152ea565b9998505050505050505050565b60808101615894828861470b565b6158a160208301876146f4565b6158ae60408301866146f4565b81810360608301526157b4818486615322565b601d81526000602082017f416464726573733a20696e73756666696369656e742062616c616e6365000000815291505b5060200190565b60208082528101610ce5816158c1565b600081610ce5565b603a81526000602082017f416464726573733a20756e61626c6520746f2073656e642076616c75652c207281527f6563697069656e74206d6179206861766520726576657274656400000000000060208201529150615065565b60208082528101610ce581615910565b8051610ce581614590565b60006020828403121561599a5761599a600080fd5b600061344c848461597a565b602e81526000602082017f45524331393637557067726164653a206e657720696d706c656d656e7461746981527f6f6e206973206e6f74205555505300000000000000000000000000000000000060208201529150615065565b60208082528101610ce5816159a6565b602981526000602082017f45524331393637557067726164653a20756e737570706f727465642070726f7881527f6961626c6555554944000000000000000000000000000000000000000000000060208201529150615065565b60208082528101610ce581615a10565b63ffffffff918216919081169082820190811115610ce557610ce5615502565b600067ffffffffffffffff8216915067ffffffffffffffff8316925081830267ffffffffffffffff8116615550565b80820180821115610ce557610ce5615502565b60008085851115615aef57615aef600080fd5b83861115615aff57615aff600080fd5b5050820193919092039150565b803582826020821015615b4d57615b487fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff836020036008021b90565b831692505b505092915050565b60006143fb6020840184614792565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe136859003018112615b9d57615b9d600080fd5b83810160208101935035915067ffffffffffffffff821115615bc157615bc1600080fd5b6020820236038313156152ba576152ba600080fd5b600060608301615be68380615b55565b615bf08582614bb5565b50615bfe6020840184615b64565b8583036020870152615c11838284615314565b92505050615c226040840184615b64565b8583036040870152614cb3838284615314565b60408101615c43828561470b565b818103602083015261344c8184615bd6565b600061344c8284866152ea565b6000615c6e82896156f2565b600882019150615c7e82886152d9565b601482019150615c8e828761470b565b602082019150615c9e828661470b565b602082019150615cae828561470b565b602082019150615cbe82846152d9565b506014019695505050505050565b602b81526000602082017f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206981527f6e697469616c697a696e6700000000000000000000000000000000000000000060208201529150615065565b60208082528101610ce581615ccc565b60808101615d448287614bb5565b615d516020830186614e62565b615d5e6040830185614bb5565b61452f606083018461470b565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081526017016000615d9d82856157e3565b7f206973206d697373696e6720726f6c65200000000000000000000000000000008152601101915061344c82846157e3565b6000615dd9825190565b808452602084019350615df08185602086016157bf565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f82011661535f565b602080825281016143fb8184615dcf565b602d81526000602082017f455243313936373a206e657720696d706c656d656e746174696f6e206973206e81527f6f74206120636f6e74726163740000000000000000000000000000000000000060208201529150615065565b60208082528101610ce581615e2c565b81810280821583820485141761556157615561615502565b600081615ebd57615ebd615502565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b60208082527f537472696e67733a20686578206c656e67746820696e73756666696369656e74910190815260006158f1565b60208082528101610ce581615ee3565b602681526000602082017f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f81527f6e7472616374000000000000000000000000000000000000000000000000000060208201529150615065565b60208082528101610ce581615f25565b60006143fb82846157e356fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212202c9073bda4a8585e646877704375504d9b77be228f1b35d596bb70aab9a8007164736f6c63430008130033

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.