FRAX Price: $1.04 (+6.86%)

Contract

0xBDB5088A8e89e9ec83e82caA01EC20Ed976459eD

Overview

FRAX Balance | FXTL Balance

0 FRAX | 71,338 FXTL

FRAX Value

$0.00

Token Holdings

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To
Transfer Ownersh...22893842024-03-25 17:57:59670 days ago1711389479IN
0xBDB5088A...d976459eD
0 FRAX0.000005260.00010025

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Block From To
22890732024-03-25 17:47:37670 days ago1711388857  Contract Creation0 FRAX

Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
L1VeFXS

Compiler Version
v0.8.20+commit.a1b79de6

Optimization Enabled:
Yes with 1000000 runs

Other Settings:
paris EvmVersion, None license
// SPDX-License-Identifier: ISC
pragma solidity ^0.8.20;

// ====================================================================
// |     ______                   _______                             |
// |    / _____________ __  __   / ____(_____  ____ _____  ________   |
// |   / /_  / ___/ __ `| |/_/  / /_  / / __ \/ __ `/ __ \/ ___/ _ \  |
// |  / __/ / /  / /_/ _>  <   / __/ / / / / / /_/ / / / / /__/  __/  |
// | /_/   /_/   \__,_/_/|_|  /_/   /_/_/ /_/\__,_/_/ /_/\___/\___/   |
// |                                                                  |
// ====================================================================
// ============================== L1VeFXS =============================
// ====================================================================

import { Ownable2StepUpgradeable } from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol";
import { MerkleTreeProver } from "./lib/MerkleTreeProver.sol";
import { StateProofVerifier as Verifier } from "./lib/StateProofVerifier.sol";
import { IPriceSourceReceiver } from "./interfaces/IPriceSourceReceiver.sol";
import { IStateRootOracle } from "./interfaces/IStateRootOracle.sol";

/// @title L1VeFXS
/// @notice Holds proved veFXS balances from L1
/// @author Frax Finance (https://github.com/fraxfinance)
contract L1VeFXS is Ownable2StepUpgradeable {
    /// @notice Slot index of the locked HashMap in the veFXS contract
    uint256 public constant LOCKED_SLOT_INDEX = 2;

    /// @notice veFXS address on L1
    address public constant veFXSAddress = 0xc8418aF6358FFddA74e09Ca9CC3Fe03Ca6aDC5b0;

    /// @notice max duration of lock = 4 years
    uint256 constant MAXTIME = 4 * 365 * 86_400;

    // keccak256(abi.encode(uint256(keccak256("frax.universal.L1VeFXS.storage")) - 1))
    bytes32 private constant AppStorageLocation = 0xc667da153497ef4116ec36eef54e190e9a94eda237a4c431c2176edb0ad62d40;

    /// @dev amount and end of lock
    struct LockedBalance {
        uint128 amount;
        uint64 end;
        uint64 blockTimestamp;
    }

    struct AppStorage {
        mapping(address => LockedBalance) locked;
        /// @notice The address of the StateRootOracle on Layer 2
        IStateRootOracle stateRootOracle;
    }

    function appStorage() private pure returns (AppStorage storage $) {
        assembly {
            $.slot := AppStorageLocation
        }
    }

    /// @notice bridged locked data
    function locked(address account) external view returns (LockedBalance memory) {
        AppStorage storage $ = appStorage();
        return $.locked[account];
    }

    /// @notice The ```veFXSUpdated ``` event is emitted when a veFXS data is updated
    /// @param addr Users address
    /// @param amount amount of FXS
    /// @param end end time of the lock
    /// @param blockTimestamp time stamp of the L1block that is used to proof the balance
    event veFXSUpdated(address indexed addr, uint128 amount, uint64 end, uint64 blockTimestamp);

    constructor() {
        _disableInitializers();
    }

    /// @param _stateRootOracle Address of the L2 StateRootOracle
    function initialize(address _stateRootOracle, address _owner) external initializer {
        // initialize only once
        AppStorage storage $ = appStorage();
        require(address($.stateRootOracle) == address(0) && _stateRootOracle != address(0));
        $.stateRootOracle = IStateRootOracle(_stateRootOracle);
        _transferOwnership(_owner);
    }

    /// @notice The ```proofVeFXS``` function uses merkle proofs to prove L1 veFXS balance.
    /// @dev Proves the storage root using block info from the L2 StateRootOracle. Then uses storage root hash to prove the amount and end lock time
    /// @param _address the address to proof the veFXS locked amounts
    /// @param _blockNumber The block number
    /// @param _accountProof The accountProof retrieved from eth_getProof
    /// @param _storageProof1 The storageProof.proof retrieved from eth_getProof, to proof the amount
    /// @param _storageProof2 The storageProof.proof retrieved from eth_getProof, to proof the end lock time
    function proofVeFXS(
        address _address,
        uint256 _blockNumber,
        bytes[] memory _accountProof,
        bytes[] memory _storageProof1,
        bytes[] memory _storageProof2
    ) external {
        AppStorage storage $ = appStorage();
        IStateRootOracle.BlockInfo memory _blockInfo = $.stateRootOracle.getBlockInfo(_blockNumber);
        require(
            _blockInfo.timestamp > $.locked[_address].blockTimestamp,
            "L1VeFXS: Can only update with later information"
        );

        Verifier.Account memory _accountPool = MerkleTreeProver.proveStorageRoot({
            stateRootHash: _blockInfo.stateRootHash,
            proofAddress: veFXSAddress,
            accountProof: _accountProof
        });

        // slot index of LockedBalance of given address
        uint256 _slot = uint256(
            keccak256(abi.encodePacked(keccak256(abi.encodePacked(LOCKED_SLOT_INDEX, uint256(uint160(_address))))))
        );

        // amount is in the first slot;
        uint256 _amount = uint256(
            MerkleTreeProver
                .proveStorageSlotValue({
                    storageRootHash: _accountPool.storageRoot,
                    slot: bytes32(_slot),
                    storageProof: _storageProof1
                })
                .value
        );
        // end is in the second slot;
        uint256 _end = uint256(
            MerkleTreeProver
                .proveStorageSlotValue({
                    storageRootHash: _accountPool.storageRoot,
                    slot: bytes32(_slot + 1),
                    storageProof: _storageProof2
                })
                .value
        );

        // Sanity checks
        require(_amount > 0, "L1VeFXS: amount is zero");
        require(_amount < uint128(type(int128).max), "L1VeFXS: amount too large");
        require(_end > block.timestamp, "L1VeFXS: lock expired");
        require(_end - block.timestamp <= MAXTIME, "L1VeFXS: lock too long");

        // Update storage
        $.locked[_address].amount = uint128(_amount);
        $.locked[_address].end = uint64(_end);
        $.locked[_address].blockTimestamp = _blockInfo.timestamp;

        // Emit events
        emit veFXSUpdated(_address, $.locked[_address].amount, $.locked[_address].end, _blockInfo.timestamp);
    }

    /// @notice Get the voting power (at current block) of a proven L1 veFXS account
    /// @param _address Account whose voting power we are querying
    /// @return _balance uint256 voting power as
    function balanceOf(address _address) external view returns (uint256 _balance) {
        AppStorage storage $ = appStorage();
        LockedBalance memory _lockedBalance = $.locked[_address];
        if (_lockedBalance.end > block.timestamp) {
            _balance =
                _lockedBalance.amount +
                (uint256(_lockedBalance.amount) * 3 * (_lockedBalance.end - block.timestamp)) /
                MAXTIME;
        }
    }

    /// @notice Utility method to allow owner to batch-add voting power balances of accounts
    /// @dev Once an account proves a balance, the owner is unable to overwrite the proven balance.
    function adminProofVeFXS(
        address[] calldata _addresses,
        LockedBalance[] calldata _lockedBalances
    ) external onlyOwner {
        AppStorage storage $ = appStorage();
        uint256 length = _addresses.length;
        if (length != _lockedBalances.length) revert UnequalLengths();

        for (uint256 i = 0; i < _addresses.length; ) {
            address _address = _addresses[i];
            LockedBalance memory _lockedBalance = _lockedBalances[i];

            // Only prove balances that have not yet been proven by users
            if ($.locked[_address].amount == 0) {
                $.locked[_address] = _lockedBalance;
                emit veFXSUpdated(_address, _lockedBalance.amount, _lockedBalance.end, _lockedBalance.blockTimestamp);
            }

            unchecked {
                ++i;
            }
        }
    }

    error UnequalLengths();
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable2Step.sol)

pragma solidity ^0.8.20;

import {OwnableUpgradeable} from "./OwnableUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module which provides access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is specified at deployment time in the constructor for `Ownable`. This
 * can later be changed with {transferOwnership} and {acceptOwnership}.
 *
 * This module is used through inheritance. It will make available all functions
 * from parent (Ownable).
 */
abstract contract Ownable2StepUpgradeable is Initializable, OwnableUpgradeable {
    /// @custom:storage-location erc7201:openzeppelin.storage.Ownable2Step
    struct Ownable2StepStorage {
        address _pendingOwner;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable2Step")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant Ownable2StepStorageLocation = 0x237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c00;

    function _getOwnable2StepStorage() private pure returns (Ownable2StepStorage storage $) {
        assembly {
            $.slot := Ownable2StepStorageLocation
        }
    }

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

    function __Ownable2Step_init() internal onlyInitializing {
    }

    function __Ownable2Step_init_unchained() internal onlyInitializing {
    }
    /**
     * @dev Returns the address of the pending owner.
     */
    function pendingOwner() public view virtual returns (address) {
        Ownable2StepStorage storage $ = _getOwnable2StepStorage();
        return $._pendingOwner;
    }

    /**
     * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual override onlyOwner {
        Ownable2StepStorage storage $ = _getOwnable2StepStorage();
        $._pendingOwner = newOwner;
        emit OwnershipTransferStarted(owner(), newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual override {
        Ownable2StepStorage storage $ = _getOwnable2StepStorage();
        delete $._pendingOwner;
        super._transferOwnership(newOwner);
    }

    /**
     * @dev The new owner accepts the ownership transfer.
     */
    function acceptOwnership() public virtual {
        address sender = _msgSender();
        if (pendingOwner() != sender) {
            revert OwnableUnauthorizedAccount(sender);
        }
        _transferOwnership(sender);
    }
}

//SPDX-License-Identifier: ISC
pragma solidity ^0.8.20;

// ====================================================================
// |     ______                   _______                             |
// |    / _____________ __  __   / ____(_____  ____ _____  ________   |
// |   / /_  / ___/ __ `| |/_/  / /_  / / __ \/ __ `/ __ \/ ___/ _ \  |
// |  / __/ / /  / /_/ _>  <   / __/ / / / / / /_/ / / / / /__/  __/  |
// | /_/   /_/   \__,_/_/|_|  /_/   /_/_/ /_/\__,_/_/ /_/\___/\___/   |
// |                                                                  |
// ====================================================================
// ========================= MerkleTreeProver =========================
// ====================================================================
// Frax Finance: https://github.com/FraxFinance

// Authors
// Jon Walch: https://github.com/jonwalch
// Dennis: https://github.com/denett

// Reviewers
// Drake Evans: https://github.com/DrakeEvans

// ====================================================================
import { RLPReader } from "rlp/RLPReader.sol";
import { StateProofVerifier as Verifier } from "./StateProofVerifier.sol";

/// @title MerkleTreeProver
/// @author Jon Walch (Frax Finance) https://github.com/jonwalch
/// @notice Helper function library for interacting with StateProofVerifier and RLPReader
library MerkleTreeProver {
    using RLPReader for bytes;
    using RLPReader for RLPReader.RLPItem;

    /// @notice The ```proveStorageRoot``` function is a helper function for StateProofVerifier.extractAccountFromProof()
    /// @param stateRootHash The hash of the state root
    /// @param proofAddress The address of the contract we're proving
    /// @param accountProof The accountProof retrieved from eth_getProof
    function proveStorageRoot(
        bytes32 stateRootHash,
        address proofAddress,
        bytes[] memory accountProof
    ) internal view returns (Verifier.Account memory accountPool) {
        RLPReader.RLPItem[] memory accountProofRlp = new RLPReader.RLPItem[](accountProof.length);
        for (uint256 i = 0; i < accountProof.length; ++i) {
            accountProofRlp[i] = accountProof[i].toRlpItem();
        }
        accountPool = Verifier.extractAccountFromProof({
            _addressHash: keccak256(abi.encodePacked(proofAddress)),
            _stateRootHash: stateRootHash,
            _proof: accountProofRlp
        });
    }

    /// @notice The ```proveStorageSlotValue``` function is a helper function for StateProofVerifier.extractSlotValueFromProof()
    /// @param storageRootHash The hash of the storage root
    /// @param slot The slot we want to prove for the contract
    /// @param storageProof The storageProof.proof retrieved from eth_getProof
    function proveStorageSlotValue(
        bytes32 storageRootHash,
        bytes32 slot,
        bytes[] memory storageProof
    ) internal view returns (Verifier.SlotValue memory slotValue) {
        RLPReader.RLPItem[] memory storageProofRlp = new RLPReader.RLPItem[](storageProof.length);
        for (uint256 i = 0; i < storageProof.length; ++i) {
            storageProofRlp[i] = storageProof[i].toRlpItem();
        }
        slotValue = Verifier.extractSlotValueFromProof({
            _slotHash: keccak256(abi.encodePacked(slot)),
            _storageRootHash: storageRootHash,
            _proof: storageProofRlp
        });
    }
}

// SPDX-License-Identifier: MIT
// Copied from https://github.com/lidofinance/curve-merkle-oracle/blob/1033b3e84142317ffd8f366b52e489d5eb49c73f/contracts/StateProofVerifier.sol
pragma solidity ^0.8.20;

import { RLPReader } from "rlp/RLPReader.sol";
import { MerklePatriciaProofVerifier } from "./MerklePatriciaProofVerifier.sol";

/**
 * @title A helper library for verification of Merkle Patricia account and state proofs.
 */
library StateProofVerifier {
    using RLPReader for RLPReader.RLPItem;
    using RLPReader for bytes;

    uint256 constant HEADER_STATE_ROOT_INDEX = 3;
    uint256 constant HEADER_NUMBER_INDEX = 8;
    uint256 constant HEADER_TIMESTAMP_INDEX = 11;

    struct BlockHeader {
        bytes32 hash;
        bytes32 stateRootHash;
        uint256 number;
        uint256 timestamp;
    }

    struct Account {
        bool exists;
        uint256 nonce;
        uint256 balance;
        bytes32 storageRoot;
        bytes32 codeHash;
    }

    struct SlotValue {
        bool exists;
        uint256 value;
    }

    /**
     * @notice Parses block header and verifies its presence onchain within the latest 256 blocks.
     * @param _headerRlpBytes RLP-encoded block header.
     */
    function verifyBlockHeader(bytes memory _headerRlpBytes) internal view returns (BlockHeader memory) {
        BlockHeader memory header = parseBlockHeader(_headerRlpBytes);
        // ensure that the block is actually in the blockchain
        require(header.hash == blockhash(header.number), "blockhash mismatch");
        return header;
    }

    /**
     * @notice Parses RLP-encoded block header.
     * @param _headerRlpBytes RLP-encoded block header.
     */
    function parseBlockHeader(bytes memory _headerRlpBytes) internal pure returns (BlockHeader memory) {
        BlockHeader memory result;
        RLPReader.RLPItem[] memory headerFields = _headerRlpBytes.toRlpItem().toList();

        require(headerFields.length > HEADER_TIMESTAMP_INDEX);

        result.stateRootHash = bytes32(headerFields[HEADER_STATE_ROOT_INDEX].toUint());
        result.number = headerFields[HEADER_NUMBER_INDEX].toUint();
        result.timestamp = headerFields[HEADER_TIMESTAMP_INDEX].toUint();
        result.hash = keccak256(_headerRlpBytes);

        return result;
    }

    /**
     * @notice Verifies Merkle Patricia proof of an account and extracts the account fields.
     *
     * @param _addressHash Keccak256 hash of the address corresponding to the account.
     * @param _stateRootHash MPT root hash of the Ethereum state trie.
     */
    function extractAccountFromProof(
        bytes32 _addressHash, // keccak256(abi.encodePacked(address))
        bytes32 _stateRootHash,
        RLPReader.RLPItem[] memory _proof
    ) internal pure returns (Account memory) {
        bytes memory acctRlpBytes = MerklePatriciaProofVerifier.extractProofValue(
            _stateRootHash,
            abi.encodePacked(_addressHash),
            _proof
        );

        Account memory account;

        if (acctRlpBytes.length == 0) {
            return account;
        }

        RLPReader.RLPItem[] memory acctFields = acctRlpBytes.toRlpItem().toList();
        require(acctFields.length == 4);

        account.exists = true;
        account.nonce = acctFields[0].toUint();
        account.balance = acctFields[1].toUint();
        account.storageRoot = bytes32(acctFields[2].toUint());
        account.codeHash = bytes32(acctFields[3].toUint());

        return account;
    }

    /**
     * @notice Verifies Merkle Patricia proof of a slot and extracts the slot's value.
     *
     * @param _slotHash Keccak256 hash of the slot position.
     * @param _storageRootHash MPT root hash of the account's storage trie.
     */
    function extractSlotValueFromProof(
        bytes32 _slotHash,
        bytes32 _storageRootHash,
        RLPReader.RLPItem[] memory _proof
    ) internal pure returns (SlotValue memory) {
        bytes memory valueRlpBytes = MerklePatriciaProofVerifier.extractProofValue(
            _storageRootHash,
            abi.encodePacked(_slotHash),
            _proof
        );

        SlotValue memory value;

        if (valueRlpBytes.length != 0) {
            value.exists = true;
            value.value = valueRlpBytes.toRlpItem().toUint();
        }

        return value;
    }
}

// SPDX-License-Identifier: ISC
pragma solidity ^0.8.20;

interface IPriceSourceReceiver {
    function addRoundData(bool isBadData, uint104 priceLow, uint104 priceHigh, uint40 timestamp) external;

    function getPrices() external view returns (bool isBadData, uint256 priceLow, uint256 priceHigh);
}

// SPDX-License-Identifier: ISC
pragma solidity ^0.8.20;

interface IStateRootOracle {
    struct BlockInfo {
        bytes32 stateRootHash;
        uint40 timestamp;
    }

    function getBlockInfo(uint256 blockNumber) external view returns (BlockInfo memory _blockInfo);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is set to the address provided by the deployer. This can
 * later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
    /// @custom:storage-location erc7201:openzeppelin.storage.Ownable
    struct OwnableStorage {
        address _owner;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300;

    function _getOwnableStorage() private pure returns (OwnableStorage storage $) {
        assembly {
            $.slot := OwnableStorageLocation
        }
    }

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

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

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

    function __Ownable_init_unchained(address initialOwner) internal onlyInitializing {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

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

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

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

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

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.20;

/**
 * @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]
 * ```solidity
 * 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 Storage of the initializable contract.
     *
     * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
     * when using with upgradeable contracts.
     *
     * @custom:storage-location erc7201:openzeppelin.storage.Initializable
     */
    struct InitializableStorage {
        /**
         * @dev Indicates that the contract has been initialized.
         */
        uint64 _initialized;
        /**
         * @dev Indicates that the contract is in the process of being initialized.
         */
        bool _initializing;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;

    /**
     * @dev The contract is already initialized.
     */
    error InvalidInitialization();

    /**
     * @dev The contract is not initializing.
     */
    error NotInitializing();

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint64 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 in the context of a constructor an `initializer` may be invoked any
     * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
     * production.
     *
     * Emits an {Initialized} event.
     */
    modifier initializer() {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        // Cache values to avoid duplicated sloads
        bool isTopLevelCall = !$._initializing;
        uint64 initialized = $._initialized;

        // Allowed calls:
        // - initialSetup: the contract is not in the initializing state and no previous version was
        //                 initialized
        // - construction: the contract is initialized at version 1 (no reininitialization) and the
        //                 current contract is just being deployed
        bool initialSetup = initialized == 0 && isTopLevelCall;
        bool construction = initialized == 1 && address(this).code.length == 0;

        if (!initialSetup && !construction) {
            revert InvalidInitialization();
        }
        $._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 2**64 - 1 will prevent any future reinitialization.
     *
     * Emits an {Initialized} event.
     */
    modifier reinitializer(uint64 version) {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        if ($._initializing || $._initialized >= version) {
            revert InvalidInitialization();
        }
        $._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() {
        _checkInitializing();
        _;
    }

    /**
     * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
     */
    function _checkInitializing() internal view virtual {
        if (!_isInitializing()) {
            revert NotInitializing();
        }
    }

    /**
     * @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 {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        if ($._initializing) {
            revert InvalidInitialization();
        }
        if ($._initialized != type(uint64).max) {
            $._initialized = type(uint64).max;
            emit Initialized(type(uint64).max);
        }
    }

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

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

    /**
     * @dev Returns a pointer to the storage namespace.
     */
    // solhint-disable-next-line var-name-mixedcase
    function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
        assembly {
            $.slot := INITIALIZABLE_STORAGE
        }
    }
}

// SPDX-License-Identifier: Apache-2.0

/*
 * @author Hamdi Allam [email protected]
 * Please reach out with any questions or concerns
 */
pragma solidity >=0.5.10 <0.9.0;

library RLPReader {
    uint8 constant STRING_SHORT_START = 0x80;
    uint8 constant STRING_LONG_START = 0xb8;
    uint8 constant LIST_SHORT_START = 0xc0;
    uint8 constant LIST_LONG_START = 0xf8;
    uint8 constant WORD_SIZE = 32;

    struct RLPItem {
        uint256 len;
        uint256 memPtr;
    }

    struct Iterator {
        RLPItem item; // Item that's being iterated over.
        uint256 nextPtr; // Position of the next item in the list.
    }

    /*
     * @dev Returns the next element in the iteration. Reverts if it has not next element.
     * @param self The iterator.
     * @return The next element in the iteration.
     */
    function next(Iterator memory self) internal pure returns (RLPItem memory) {
        require(hasNext(self));

        uint256 ptr = self.nextPtr;
        uint256 itemLength = _itemLength(ptr);
        self.nextPtr = ptr + itemLength;

        return RLPItem(itemLength, ptr);
    }

    /*
     * @dev Returns true if the iteration has more elements.
     * @param self The iterator.
     * @return true if the iteration has more elements.
     */
    function hasNext(Iterator memory self) internal pure returns (bool) {
        RLPItem memory item = self.item;
        return self.nextPtr < item.memPtr + item.len;
    }

    /*
     * @param item RLP encoded bytes
     */
    function toRlpItem(bytes memory item) internal pure returns (RLPItem memory) {
        uint256 memPtr;
        assembly {
            memPtr := add(item, 0x20)
        }

        return RLPItem(item.length, memPtr);
    }

    /*
     * @dev Create an iterator. Reverts if item is not a list.
     * @param self The RLP item.
     * @return An 'Iterator' over the item.
     */
    function iterator(RLPItem memory self) internal pure returns (Iterator memory) {
        require(isList(self));

        uint256 ptr = self.memPtr + _payloadOffset(self.memPtr);
        return Iterator(self, ptr);
    }

    /*
     * @param the RLP item.
     */
    function rlpLen(RLPItem memory item) internal pure returns (uint256) {
        return item.len;
    }

    /*
     * @param the RLP item.
     * @return (memPtr, len) pair: location of the item's payload in memory.
     */
    function payloadLocation(RLPItem memory item) internal pure returns (uint256, uint256) {
        uint256 offset = _payloadOffset(item.memPtr);
        uint256 memPtr = item.memPtr + offset;
        uint256 len = item.len - offset; // data length
        return (memPtr, len);
    }

    /*
     * @param the RLP item.
     */
    function payloadLen(RLPItem memory item) internal pure returns (uint256) {
        (, uint256 len) = payloadLocation(item);
        return len;
    }

    /*
     * @param the RLP item containing the encoded list.
     */
    function toList(RLPItem memory item) internal pure returns (RLPItem[] memory) {
        require(isList(item));

        uint256 items = numItems(item);
        RLPItem[] memory result = new RLPItem[](items);

        uint256 memPtr = item.memPtr + _payloadOffset(item.memPtr);
        uint256 dataLen;
        for (uint256 i = 0; i < items; i++) {
            dataLen = _itemLength(memPtr);
            result[i] = RLPItem(dataLen, memPtr);
            memPtr = memPtr + dataLen;
        }

        return result;
    }

    // @return indicator whether encoded payload is a list. negate this function call for isData.
    function isList(RLPItem memory item) internal pure returns (bool) {
        if (item.len == 0) return false;

        uint8 byte0;
        uint256 memPtr = item.memPtr;
        assembly {
            byte0 := byte(0, mload(memPtr))
        }

        if (byte0 < LIST_SHORT_START) return false;
        return true;
    }

    /*
     * @dev A cheaper version of keccak256(toRlpBytes(item)) that avoids copying memory.
     * @return keccak256 hash of RLP encoded bytes.
     */
    function rlpBytesKeccak256(RLPItem memory item) internal pure returns (bytes32) {
        uint256 ptr = item.memPtr;
        uint256 len = item.len;
        bytes32 result;
        assembly {
            result := keccak256(ptr, len)
        }
        return result;
    }

    /*
     * @dev A cheaper version of keccak256(toBytes(item)) that avoids copying memory.
     * @return keccak256 hash of the item payload.
     */
    function payloadKeccak256(RLPItem memory item) internal pure returns (bytes32) {
        (uint256 memPtr, uint256 len) = payloadLocation(item);
        bytes32 result;
        assembly {
            result := keccak256(memPtr, len)
        }
        return result;
    }

    /** RLPItem conversions into data types **/

    // @returns raw rlp encoding in bytes
    function toRlpBytes(RLPItem memory item) internal pure returns (bytes memory) {
        bytes memory result = new bytes(item.len);
        if (result.length == 0) return result;

        uint256 ptr;
        assembly {
            ptr := add(0x20, result)
        }

        copy(item.memPtr, ptr, item.len);
        return result;
    }

    // any non-zero byte except "0x80" is considered true
    function toBoolean(RLPItem memory item) internal pure returns (bool) {
        require(item.len == 1);
        uint256 result;
        uint256 memPtr = item.memPtr;
        assembly {
            result := byte(0, mload(memPtr))
        }

        // SEE Github Issue #5.
        // Summary: Most commonly used RLP libraries (i.e Geth) will encode
        // "0" as "0x80" instead of as "0". We handle this edge case explicitly
        // here.
        if (result == 0 || result == STRING_SHORT_START) {
            return false;
        } else {
            return true;
        }
    }

    function toAddress(RLPItem memory item) internal pure returns (address) {
        // 1 byte for the length prefix
        require(item.len == 21);

        return address(uint160(toUint(item)));
    }

    function toUint(RLPItem memory item) internal pure returns (uint256) {
        require(item.len > 0 && item.len <= 33);

        (uint256 memPtr, uint256 len) = payloadLocation(item);

        uint256 result;
        assembly {
            result := mload(memPtr)

            // shift to the correct location if neccesary
            if lt(len, 32) {
                result := div(result, exp(256, sub(32, len)))
            }
        }

        return result;
    }

    // enforces 32 byte length
    function toUintStrict(RLPItem memory item) internal pure returns (uint256) {
        // one byte prefix
        require(item.len == 33);

        uint256 result;
        uint256 memPtr = item.memPtr + 1;
        assembly {
            result := mload(memPtr)
        }

        return result;
    }

    function toBytes(RLPItem memory item) internal pure returns (bytes memory) {
        require(item.len > 0);

        (uint256 memPtr, uint256 len) = payloadLocation(item);
        bytes memory result = new bytes(len);

        uint256 destPtr;
        assembly {
            destPtr := add(0x20, result)
        }

        copy(memPtr, destPtr, len);
        return result;
    }

    /*
     * Private Helpers
     */

    // @return number of payload items inside an encoded list.
    function numItems(RLPItem memory item) private pure returns (uint256) {
        if (item.len == 0) return 0;

        uint256 count = 0;
        uint256 currPtr = item.memPtr + _payloadOffset(item.memPtr);
        uint256 endPtr = item.memPtr + item.len;
        while (currPtr < endPtr) {
            currPtr = currPtr + _itemLength(currPtr); // skip over an item
            count++;
        }

        return count;
    }

    // @return entire rlp item byte length
    function _itemLength(uint256 memPtr) private pure returns (uint256) {
        uint256 itemLen;
        uint256 byte0;
        assembly {
            byte0 := byte(0, mload(memPtr))
        }

        if (byte0 < STRING_SHORT_START) {
            itemLen = 1;
        } else if (byte0 < STRING_LONG_START) {
            itemLen = byte0 - STRING_SHORT_START + 1;
        } else if (byte0 < LIST_SHORT_START) {
            assembly {
                let byteLen := sub(byte0, 0xb7) // # of bytes the actual length is
                memPtr := add(memPtr, 1) // skip over the first byte

                /* 32 byte word size */
                let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to get the len
                itemLen := add(dataLen, add(byteLen, 1))
            }
        } else if (byte0 < LIST_LONG_START) {
            itemLen = byte0 - LIST_SHORT_START + 1;
        } else {
            assembly {
                let byteLen := sub(byte0, 0xf7)
                memPtr := add(memPtr, 1)

                let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to the correct length
                itemLen := add(dataLen, add(byteLen, 1))
            }
        }

        return itemLen;
    }

    // @return number of bytes until the data
    function _payloadOffset(uint256 memPtr) private pure returns (uint256) {
        uint256 byte0;
        assembly {
            byte0 := byte(0, mload(memPtr))
        }

        if (byte0 < STRING_SHORT_START) {
            return 0;
        } else if (byte0 < STRING_LONG_START || (byte0 >= LIST_SHORT_START && byte0 < LIST_LONG_START)) {
            return 1;
        } else if (byte0 < LIST_SHORT_START) {
            // being explicit
            return byte0 - (STRING_LONG_START - 1) + 1;
        } else {
            return byte0 - (LIST_LONG_START - 1) + 1;
        }
    }

    /*
     * @param src Pointer to source
     * @param dest Pointer to destination
     * @param len Amount of memory to copy from the source
     */
    function copy(uint256 src, uint256 dest, uint256 len) private pure {
        if (len == 0) return;

        // copy as many word sizes as possible
        for (; len >= WORD_SIZE; len -= WORD_SIZE) {
            assembly {
                mstore(dest, mload(src))
            }

            src += WORD_SIZE;
            dest += WORD_SIZE;
        }

        if (len > 0) {
            // left over bytes. Mask is used to remove unwanted bytes from the word
            uint256 mask = 256**(WORD_SIZE - len) - 1;
            assembly {
                let srcpart := and(mload(src), not(mask)) // zero out src
                let destpart := and(mload(dest), mask) // retrieve the bytes
                mstore(dest, or(destpart, srcpart))
            }
        }
    }
}

// SPDX-License-Identifier: MIT
// Copied from https://github.com/lidofinance/curve-merkle-oracle/blob/1033b3e84142317ffd8f366b52e489d5eb49c73f/contracts/MerklePatriciaProofVerifier.sol
/**
 * Copied from https://github.com/lorenzb/proveth/blob/c74b20e/onchain/ProvethVerifier.sol
 * with minor performance and code style-related modifications.
 */
pragma solidity ^0.8.20;

import { RLPReader } from "rlp/RLPReader.sol";

library MerklePatriciaProofVerifier {
    using RLPReader for RLPReader.RLPItem;
    using RLPReader for bytes;

    /// @dev Validates a Merkle-Patricia-Trie proof.
    ///      If the proof proves the inclusion of some key-value pair in the
    ///      trie, the value is returned. Otherwise, i.e. if the proof proves
    ///      the exclusion of a key from the trie, an empty byte array is
    ///      returned.
    /// @param rootHash is the Keccak-256 hash of the root node of the MPT.
    /// @param path is the key of the node whose inclusion/exclusion we are
    ///        proving.
    /// @param stack is the stack of MPT nodes (starting with the root) that
    ///        need to be traversed during verification.
    /// @return value whose inclusion is proved or an empty byte array for
    ///         a proof of exclusion
    function extractProofValue(
        bytes32 rootHash,
        bytes memory path,
        RLPReader.RLPItem[] memory stack
    ) internal pure returns (bytes memory value) {
        bytes memory mptKey = _decodeNibbles(path, 0);
        uint256 mptKeyOffset = 0;

        bytes32 nodeHashHash;
        RLPReader.RLPItem[] memory node;

        RLPReader.RLPItem memory rlpValue;

        if (stack.length == 0) {
            // Root hash of empty Merkle-Patricia-Trie
            require(rootHash == 0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421);
            return new bytes(0);
        }

        // Traverse stack of nodes starting at root.
        for (uint256 i = 0; i < stack.length; i++) {
            // We use the fact that an rlp encoded list consists of some
            // encoding of its length plus the concatenation of its
            // *rlp-encoded* items.

            // The root node is hashed with Keccak-256 ...
            if (i == 0 && rootHash != stack[i].rlpBytesKeccak256()) {
                revert();
            }
            // ... whereas all other nodes are hashed with the MPT
            // hash function.
            if (i != 0 && nodeHashHash != _mptHashHash(stack[i])) {
                revert();
            }
            // We verified that stack[i] has the correct hash, so we
            // may safely decode it.
            node = stack[i].toList();

            if (node.length == 2) {
                // Extension or Leaf node

                bool isLeaf;
                bytes memory nodeKey;
                (isLeaf, nodeKey) = _merklePatriciaCompactDecode(node[0].toBytes());

                uint256 prefixLength = _sharedPrefixLength(mptKeyOffset, mptKey, nodeKey);
                mptKeyOffset += prefixLength;

                if (prefixLength < nodeKey.length) {
                    // Proof claims divergent extension or leaf. (Only
                    // relevant for proofs of exclusion.)
                    // An Extension/Leaf node is divergent iff it "skips" over
                    // the point at which a Branch node should have been had the
                    // excluded key been included in the trie.
                    // Example: Imagine a proof of exclusion for path [1, 4],
                    // where the current node is a Leaf node with
                    // path [1, 3, 3, 7]. For [1, 4] to be included, there
                    // should have been a Branch node at [1] with a child
                    // at 3 and a child at 4.

                    // Sanity check
                    if (i < stack.length - 1) {
                        // divergent node must come last in proof
                        revert();
                    }

                    return new bytes(0);
                }

                if (isLeaf) {
                    // Sanity check
                    if (i < stack.length - 1) {
                        // leaf node must come last in proof
                        revert();
                    }

                    if (mptKeyOffset < mptKey.length) {
                        return new bytes(0);
                    }

                    rlpValue = node[1];
                    return rlpValue.toBytes();
                } else {
                    // extension
                    // Sanity check
                    if (i == stack.length - 1) {
                        // shouldn't be at last level
                        revert();
                    }

                    if (!node[1].isList()) {
                        // rlp(child) was at least 32 bytes. node[1] contains
                        // Keccak256(rlp(child)).
                        nodeHashHash = node[1].payloadKeccak256();
                    } else {
                        // rlp(child) was less than 32 bytes. node[1] contains
                        // rlp(child).
                        nodeHashHash = node[1].rlpBytesKeccak256();
                    }
                }
            } else if (node.length == 17) {
                // Branch node

                if (mptKeyOffset != mptKey.length) {
                    // we haven't consumed the entire path, so we need to look at a child
                    uint8 nibble = uint8(mptKey[mptKeyOffset]);
                    mptKeyOffset += 1;
                    if (nibble >= 16) {
                        // each element of the path has to be a nibble
                        revert();
                    }

                    if (_isEmptyBytesequence(node[nibble])) {
                        // Sanity
                        if (i != stack.length - 1) {
                            // leaf node should be at last level
                            revert();
                        }

                        return new bytes(0);
                    } else if (!node[nibble].isList()) {
                        nodeHashHash = node[nibble].payloadKeccak256();
                    } else {
                        nodeHashHash = node[nibble].rlpBytesKeccak256();
                    }
                } else {
                    // we have consumed the entire mptKey, so we need to look at what's contained in this node.

                    // Sanity
                    if (i != stack.length - 1) {
                        // should be at last level
                        revert();
                    }

                    return node[16].toBytes();
                }
            }
        }
    }

    /// @dev Computes the hash of the Merkle-Patricia-Trie hash of the RLP item.
    ///      Merkle-Patricia-Tries use a weird "hash function" that outputs
    ///      *variable-length* hashes: If the item is shorter than 32 bytes,
    ///      the MPT hash is the item. Otherwise, the MPT hash is the
    ///      Keccak-256 hash of the item.
    ///      The easiest way to compare variable-length byte sequences is
    ///      to compare their Keccak-256 hashes.
    /// @param item The RLP item to be hashed.
    /// @return Keccak-256(MPT-hash(item))
    function _mptHashHash(RLPReader.RLPItem memory item) private pure returns (bytes32) {
        if (item.len < 32) {
            return item.rlpBytesKeccak256();
        } else {
            return keccak256(abi.encodePacked(item.rlpBytesKeccak256()));
        }
    }

    function _isEmptyBytesequence(RLPReader.RLPItem memory item) private pure returns (bool) {
        if (item.len != 1) {
            return false;
        }
        uint8 b;
        uint256 memPtr = item.memPtr;
        assembly {
            b := byte(0, mload(memPtr))
        }
        return b == 0x80; /* empty byte string */
    }

    function _merklePatriciaCompactDecode(
        bytes memory compact
    ) private pure returns (bool isLeaf, bytes memory nibbles) {
        require(compact.length > 0);
        uint256 first_nibble = (uint8(compact[0]) >> 4) & 0xF;
        uint256 skipNibbles;
        if (first_nibble == 0) {
            skipNibbles = 2;
            isLeaf = false;
        } else if (first_nibble == 1) {
            skipNibbles = 1;
            isLeaf = false;
        } else if (first_nibble == 2) {
            skipNibbles = 2;
            isLeaf = true;
        } else if (first_nibble == 3) {
            skipNibbles = 1;
            isLeaf = true;
        } else {
            // Not supposed to happen!
            revert();
        }
        return (isLeaf, _decodeNibbles(compact, skipNibbles));
    }

    function _decodeNibbles(bytes memory compact, uint256 skipNibbles) private pure returns (bytes memory nibbles) {
        require(compact.length > 0);

        uint256 length = compact.length * 2;
        require(skipNibbles <= length);
        length -= skipNibbles;

        nibbles = new bytes(length);
        uint256 nibblesLength = 0;

        for (uint256 i = skipNibbles; i < skipNibbles + length; i += 1) {
            if (i % 2 == 0) {
                nibbles[nibblesLength] = bytes1((uint8(compact[i / 2]) >> 4) & 0xF);
            } else {
                nibbles[nibblesLength] = bytes1((uint8(compact[i / 2]) >> 0) & 0xF);
            }
            nibblesLength += 1;
        }

        assert(nibblesLength == nibbles.length);
    }

    function _sharedPrefixLength(uint256 xsOffset, bytes memory xs, bytes memory ys) private pure returns (uint256) {
        uint256 i;
        for (i = 0; i + xsOffset < xs.length && i < ys.length; i++) {
            if (xs[i + xsOffset] != ys[i]) {
                return i;
            }
        }
        return i;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;
import {Initializable} from "../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;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

Settings
{
  "remappings": [
    "ds-test/=node_modules/ds-test/src/",
    "forge-std/=node_modules/forge-std/src/",
    "frax-std/=node_modules/frax-standard-solidity/src/",
    "script/=src/script/",
    "src/=src/",
    "test/=src/test/",
    "interfaces/=src/contracts/interfaces/",
    "arbitrum/=node_modules/@arbitrum/",
    "rlp/=node_modules/solidity-rlp/contracts/",
    "@solmate/=node_modules/@rari-capital/solmate/src/",
    "@openzeppelin/=node_modules/@openzeppelin/",
    "@arbitrum/=node_modules/@arbitrum/",
    "@chainlink/=node_modules/@chainlink/",
    "@eth-optimism/=node_modules/@eth-optimism/",
    "@mean-finance/=node_modules/@mean-finance/",
    "@offchainlabs/=node_modules/@offchainlabs/",
    "@rari-capital/=node_modules/@rari-capital/",
    "@uniswap/=node_modules/@uniswap/",
    "base64-sol/=node_modules/base64-sol/",
    "frax-standard-solidity/=node_modules/frax-standard-solidity/",
    "hardhat/=node_modules/hardhat/",
    "prb-math/=node_modules/prb-math/",
    "solidity-bytes-utils/=node_modules/solidity-bytes-utils/",
    "solidity-rlp/=node_modules/solidity-rlp/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 1000000
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "none",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "viaIR": false,
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"UnequalLengths","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"addr","type":"address"},{"indexed":false,"internalType":"uint128","name":"amount","type":"uint128"},{"indexed":false,"internalType":"uint64","name":"end","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"blockTimestamp","type":"uint64"}],"name":"veFXSUpdated","type":"event"},{"inputs":[],"name":"LOCKED_SLOT_INDEX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_addresses","type":"address[]"},{"components":[{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"uint64","name":"end","type":"uint64"},{"internalType":"uint64","name":"blockTimestamp","type":"uint64"}],"internalType":"struct L1VeFXS.LockedBalance[]","name":"_lockedBalances","type":"tuple[]"}],"name":"adminProofVeFXS","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"_balance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_stateRootOracle","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"locked","outputs":[{"components":[{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"uint64","name":"end","type":"uint64"},{"internalType":"uint64","name":"blockTimestamp","type":"uint64"}],"internalType":"struct L1VeFXS.LockedBalance","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"},{"internalType":"uint256","name":"_blockNumber","type":"uint256"},{"internalType":"bytes[]","name":"_accountProof","type":"bytes[]"},{"internalType":"bytes[]","name":"_storageProof1","type":"bytes[]"},{"internalType":"bytes[]","name":"_storageProof2","type":"bytes[]"}],"name":"proofVeFXS","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"veFXSAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

60806040523480156200001157600080fd5b506200001c62000022565b620000d6565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff1615620000735760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b0390811614620000d35780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b61290180620000e66000396000f3fe608060405234801561001057600080fd5b50600436106100d45760003560e01c80638da5cb5b11610081578063cc275e8d1161005b578063cc275e8d146102a2578063e30c3978146102b5578063f2fde38b146102bd57600080fd5b80638da5cb5b14610177578063cbd006e31461017f578063cbf9fe5f1461018757600080fd5b8063715018a6116100b2578063715018a61461015457806379ba50971461015c5780637eff66661461016457600080fd5b80633c45b87c146100d9578063485cc9551461011e57806370a0823114610133575b600080fd5b6100f473c8418af6358ffdda74e09ca9cc3fe03ca6adc5b081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b61013161012c366004612211565b6102d0565b005b610146610141366004612244565b610519565b604051908152602001610115565b61013161064b565b61013161065f565b61013161017236600461225f565b6106df565b6100f4610901565b610146600281565b61025c610195366004612244565b60408051606080820183526000808352602080840182905292840181905273ffffffffffffffffffffffffffffffffffffffff9490941684527fc667da153497ef4116ec36eef54e190e9a94eda237a4c431c2176edb0ad62d4082529282902082519384018352546fffffffffffffffffffffffffffffffff8116845267ffffffffffffffff700100000000000000000000000000000000820481169285019290925278010000000000000000000000000000000000000000000000009004169082015290565b6040805182516fffffffffffffffffffffffffffffffff16815260208084015167ffffffffffffffff908116918301919091529282015190921690820152606001610115565b6101316102b03660046124b8565b610943565b6100f4610ecd565b6101316102cb366004612244565b610ef6565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff16159067ffffffffffffffff1660008115801561031b5750825b905060008267ffffffffffffffff1660011480156103385750303b155b905081158015610346575080155b1561037d576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84547fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000016600117855583156103de5784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff16680100000000000000001785555b7fc667da153497ef4116ec36eef54e190e9a94eda237a4c431c2176edb0ad62d41547fc667da153497ef4116ec36eef54e190e9a94eda237a4c431c2176edb0ad62d409073ffffffffffffffffffffffffffffffffffffffff1615801561045a575073ffffffffffffffffffffffffffffffffffffffff881615155b61046357600080fd5b6001810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8a161790556104ae87610fad565b5083156105105784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50505050505050565b73ffffffffffffffffffffffffffffffffffffffff811660009081527fc667da153497ef4116ec36eef54e190e9a94eda237a4c431c2176edb0ad62d4060208181526040808420815160608101835290546fffffffffffffffffffffffffffffffff8116825267ffffffffffffffff70010000000000000000000000000000000082048116948301859052780100000000000000000000000000000000000000000000000090910416918101919091529042101561064457630784ce0042826020015167ffffffffffffffff166105f0919061258a565b825161060f906fffffffffffffffffffffffffffffffff16600361259d565b610619919061259d565b61062391906125e3565b815161064191906fffffffffffffffffffffffffffffffff166125f7565b92505b5050919050565b610653611001565b61065d6000610fad565b565b3380610669610ecd565b73ffffffffffffffffffffffffffffffffffffffff16146106d3576040517f118cdaa700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024015b60405180910390fd5b6106dc81610fad565b50565b6106e7611001565b7fc667da153497ef4116ec36eef54e190e9a94eda237a4c431c2176edb0ad62d4083828114610742576040517fccab218c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b858110156105105760008787838181106107615761076161260a565b90506020020160208101906107769190612244565b9050600086868481811061078c5761078c61260a565b9050606002018036038101906107a29190612651565b73ffffffffffffffffffffffffffffffffffffffff83166000908152602087905260408120549192506fffffffffffffffffffffffffffffffff90911690036108f75773ffffffffffffffffffffffffffffffffffffffff8216600081815260208781526040918290208451815486840151878601516fffffffffffffffffffffffffffffffff9093167fffffffffffffffff000000000000000000000000000000000000000000000000909216821770010000000000000000000000000000000067ffffffffffffffff9283169081029190911777ffffffffffffffffffffffffffffffffffffffffffffffff1678010000000000000000000000000000000000000000000000009290941691820293909317909355845190815292830152918101919091527fd27db32ad6a2e889fcb35d08e573d9fd7c1bbed92246d3899fd73a80447900919060600160405180910390a25b5050600101610745565b6000807f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c1993005b5473ffffffffffffffffffffffffffffffffffffffff1692915050565b60007fc667da153497ef4116ec36eef54e190e9a94eda237a4c431c2176edb0ad62d4060018101546040517fbb141cf40000000000000000000000000000000000000000000000000000000081526004810188905291925060009173ffffffffffffffffffffffffffffffffffffffff9091169063bb141cf4906024016040805180830381865afa1580156109dc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a0091906126d4565b73ffffffffffffffffffffffffffffffffffffffff881660009081526020848152604090912054908201519192507801000000000000000000000000000000000000000000000000900467ffffffffffffffff1664ffffffffff90911611610aea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4c3156654658533a2043616e206f6e6c79207570646174652077697468206c6160448201527f74657220696e666f726d6174696f6e000000000000000000000000000000000060648201526084016106ca565b6000610b0f826000015173c8418af6358ffdda74e09ca9cc3fe03ca6adc5b088611059565b9050600060028973ffffffffffffffffffffffffffffffffffffffff16604051602001610b46929190918252602082015260400190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152828252805160209182012090830152016040516020818303038152906040528051906020012060001c90506000610bb083606001518360001b896111c9565b6020015190506000610bd38460600151846001610bcd91906125f7565b896111c9565b60200151905060008211610c43576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f4c3156654658533a20616d6f756e74206973207a65726f00000000000000000060448201526064016106ca565b6f7fffffffffffffffffffffffffffffff8210610cbc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4c3156654658533a20616d6f756e7420746f6f206c617267650000000000000060448201526064016106ca565b428111610d25576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4c3156654658533a206c6f636b2065787069726564000000000000000000000060448201526064016106ca565b630784ce00610d34428361258a565b1115610d9c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4c3156654658533a206c6f636b20746f6f206c6f6e670000000000000000000060448201526064016106ca565b73ffffffffffffffffffffffffffffffffffffffff8b16600081815260208881526040918290208054898301516fffffffffffffffffffffffffffffffff8881167fffffffffffffffff0000000000000000000000000000000000000000000000009093169290921770010000000000000000000000000000000067ffffffffffffffff89811682029290921777ffffffffffffffffffffffffffffffffffffffffffffffff811664ffffffffff909416780100000000000000000000000000000000000000000000000081029485179687905588519186169590941694909417845290930490921692810192909252918101919091527fd27db32ad6a2e889fcb35d08e573d9fd7c1bbed92246d3899fd73a80447900919060600160405180910390a25050505050505050505050565b6000807f237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c00610926565b610efe611001565b7f237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c0080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081178255610f67610901565b73ffffffffffffffffffffffffffffffffffffffff167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a35050565b7f237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c0080547fffffffffffffffffffffffff0000000000000000000000000000000000000000168155610ffd826112c4565b5050565b3361100a610901565b73ffffffffffffffffffffffffffffffffffffffff161461065d576040517f118cdaa70000000000000000000000000000000000000000000000000000000081523360048201526024016106ca565b6040805160a0810182526000808252602082018190529181018290526060810182905260808101919091526000825167ffffffffffffffff8111156110a0576110a0612327565b6040519080825280602002602001820160405280156110e557816020015b60408051808201909152600080825260208201528152602001906001900390816110be5790505b50905060005b835181101561116c5761113e8482815181106111095761110961260a565b602002602001015160408051808201825260008082526020918201528151808301909252825182529182019181019190915290565b8282815181106111505761115061260a565b60200260200101819052508061116590612734565b90506110eb565b506040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606086901b1660208201526111c09060340160405160208183030381529060405280519060200120868361135a565b95945050505050565b60408051808201909152600080825260208201526000825167ffffffffffffffff8111156111f9576111f9612327565b60405190808252806020026020018201604052801561123e57816020015b60408051808201909152600080825260208201528152602001906001900390816112175790505b50905060005b8351811015611290576112628482815181106111095761110961260a565b8282815181106112745761127461260a565b60200260200101819052508061128990612734565b9050611244565b506111c0846040516020016112a791815260200190565b6040516020818303038152906040528051906020012086836114d1565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080547fffffffffffffffffffffffff0000000000000000000000000000000000000000811673ffffffffffffffffffffffffffffffffffffffff848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915260006113b3848660405160200161139e91815260200190565b6040516020818303038152906040528561155e565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915290915081516000036113f35791506114ca9050565b600061142e6114298460408051808201825260008082526020918201528151808301909252825182529182019181019190915290565b61199a565b9050805160041461143e57600080fd5b6001825280516114669082906000906114595761145961260a565b6020026020010151611ab0565b6020830152805161148490829060019081106114595761145961260a565b604083015280516114a290829060029081106114595761145961260a565b606083015280516114c090829060039081106114595761145961260a565b6080830152509150505b9392505050565b604080518082019091526000808252602082015260006114fe848660405160200161139e91815260200190565b60408051808201909152600080825260208201529091508151156111c0576001815260408051808201825260008082526020918201528151808301909252835182528084019082015261155090611ab0565b602082015295945050505050565b6060600061156d846000611afe565b90506000806060611591604051806040016040528060008152602001600081525090565b86516000036115e2577f56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b42189146115c657600080fd5b505060408051600081526020810190915293506114ca92505050565b60005b875181101561198d5780158015611624575061162088828151811061160c5761160c61260a565b602002602001015160208101519051902090565b8a14155b1561162e57600080fd5b801580159061165e575061165a88828151811061164d5761164d61260a565b6020026020010151611cd4565b8414155b1561166857600080fd5b61168a88828151811061167d5761167d61260a565b602002602001015161199a565b9250825160020361183657600060606116c46116bf866000815181106116b2576116b261260a565b6020026020010151611d30565b611dae565b909250905060006116d6888a84611e49565b90506116e281896125f7565b975081518110156117455760018b516116fb919061258a565b84101561170757600080fd5b60005b6040519080825280601f01601f191660200182016040528015611734576020820181803683370190505b5099505050505050505050506114ca565b82156117ab5760018b51611759919061258a565b84101561176557600080fd5b885188101561177557600061170a565b856001815181106117885761178861260a565b6020026020010151945061179b85611d30565b99505050505050505050506114ca565b60018b516117b9919061258a565b84036117c457600080fd5b6117e7866001815181106117da576117da61260a565b6020026020010151611f04565b6118155761180e866001815181106118015761180161260a565b6020026020010151611f3f565b965061182e565b61182b8660018151811061160c5761160c61260a565b96505b50505061197b565b825160110361197b578551851461193f57600086868151811061185b5761185b61260a565b016020015160f81c90506118706001876125f7565b955060108160ff161061188257600080fd5b6118a7848260ff168151811061189a5761189a61260a565b6020026020010151611f57565b156118e357600189516118ba919061258a565b82146118c557600080fd5b505060408051600081526020810190915295506114ca945050505050565b6118fb848260ff16815181106117da576117da61260a565b61191e57611917848260ff16815181106118015761180161260a565b9450611939565b611936848260ff168151811061160c5761160c61260a565b94505b5061197b565b6001885161194d919061258a565b811461195857600080fd5b61196e836010815181106116b2576116b261260a565b96505050505050506114ca565b8061198581612734565b9150506115e5565b5050505050509392505050565b60606119a582611f04565b6119ae57600080fd5b60006119b983611f7a565b905060008167ffffffffffffffff8111156119d6576119d6612327565b604051908082528060200260200182016040528015611a1b57816020015b60408051808201909152600080825260208201528152602001906001900390816119f45790505b5090506000611a2d8560200151611fff565b8560200151611a3c91906125f7565b90506000805b84811015611aa557611a538361207a565b9150604051806040016040528083815260200184815250848281518110611a7c57611a7c61260a565b6020908102919091010152611a9182846125f7565b925080611a9d81612734565b915050611a42565b509195945050505050565b805160009015801590611ac557508151602110155b611ace57600080fd5b600080611ada84612123565b815191935091506020821015611af65760208290036101000a90045b949350505050565b60606000835111611b0e57600080fd5b600083516002611b1e919061259d565b905080831115611b2d57600080fd5b611b37838261258a565b90508067ffffffffffffffff811115611b5257611b52612327565b6040519080825280601f01601f191660200182016040528015611b7c576020820181803683370190505b5091506000835b611b8d83866125f7565b811015611cbb57611b9f60028261276c565b600003611c2357600486611bb46002846125e3565b81518110611bc457611bc461260a565b602001015160f81c60f81b60f81c60ff16901c600f1660f81b848381518110611bef57611bef61260a565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350611c9c565b600086611c316002846125e3565b81518110611c4157611c4161260a565b602001015160f81c60f81b60f81c60ff16901c600f1660f81b848381518110611c6c57611c6c61260a565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053505b611ca76001836125f7565b9150611cb46001826125f7565b9050611b83565b5082518114611ccc57611ccc612780565b505092915050565b6000602082600001511015611cf3576020820151825190205b92915050565b602082015182519020604051602001611d0e91815260200190565b604051602081830303815290604052805190602001209050919050565b919050565b8051606090611d3e57600080fd5b600080611d4a84612123565b9150915060008167ffffffffffffffff811115611d6957611d69612327565b6040519080825280601f01601f191660200182016040528015611d93576020820181803683370190505b50905060208101611da584828561216a565b50949350505050565b600060606000835111611dc057600080fd5b6000600484600081518110611dd757611dd761260a565b60209101015160f81c901c600f1690506000818103611dfc5750600092506002611e33565b81600103611e105750600092506001611e33565b81600203611e245750600192506002611e33565b816003036100d4575060019250825b83611e3e8683611afe565b935093505050915091565b6000805b8351611e5986836125f7565b108015611e665750825181105b15611af657828181518110611e7d57611e7d61260a565b01602001517fff000000000000000000000000000000000000000000000000000000000000001684611eaf87846125f7565b81518110611ebf57611ebf61260a565b01602001517fff000000000000000000000000000000000000000000000000000000000000001614611ef25790506114ca565b80611efc81612734565b915050611e4d565b80516000908103611f1757506000919050565b6020820151805160001a9060c0821015611f35575060009392505050565b5060019392505050565b6000806000611f4d84612123565b9020949350505050565b8051600090600114611f6b57506000919050565b50602001515160001a60801490565b80516000908103611f8d57506000919050565b600080611f9d8460200151611fff565b8460200151611fac91906125f7565b9050600084600001518560200151611fc491906125f7565b90505b80821015611ff657611fd88261207a565b611fe290836125f7565b915082611fee81612734565b935050611fc7565b50909392505050565b8051600090811a60808110156120185750600092915050565b60b8811080612033575060c08110801590612033575060f881105b156120415750600192915050565b60c081101561206e57612056600160b86127af565b6120639060ff168261258a565b6114ca9060016125f7565b612056600160f86127af565b80516000908190811a6080811015612095576001915061211c565b60b88110156120bb576120a960808261258a565b6120b49060016125f7565b915061211c565b60c08110156120e85760b78103600185019450806020036101000a8551046001820181019350505061211c565b60f88110156120fc576120a960c08261258a565b60f78103600185019450806020036101000a855104600182018101935050505b5092915050565b60008060006121358460200151611fff565b9050600081856020015161214991906125f7565b9050600082866000015161215d919061258a565b9196919550909350505050565b8060000361217757505050565b602081106121af578251825261218e6020846125f7565b925061219b6020836125f7565b91506121a860208261258a565b9050612177565b80156121e857600060016121c483602061258a565b6121d0906101006128e8565b6121da919061258a565b845184518216911916178352505b505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611d2b57600080fd5b6000806040838503121561222457600080fd5b61222d836121ed565b915061223b602084016121ed565b90509250929050565b60006020828403121561225657600080fd5b6114ca826121ed565b6000806000806040858703121561227557600080fd5b843567ffffffffffffffff8082111561228d57600080fd5b818701915087601f8301126122a157600080fd5b8135818111156122b057600080fd5b8860208260051b85010111156122c557600080fd5b6020928301965094509086013590808211156122e057600080fd5b818701915087601f8301126122f457600080fd5b81358181111561230357600080fd5b88602060608302850101111561231857600080fd5b95989497505060200194505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561239d5761239d612327565b604052919050565b6000601f83818401126123b757600080fd5b8235602067ffffffffffffffff808311156123d4576123d4612327565b8260051b6123e3838201612356565b93845286810183019383810190898611156123fd57600080fd5b84890192505b858310156124ab5782358481111561241b5760008081fd5b8901603f81018b1361242d5760008081fd5b8581013560408682111561244357612443612327565b612472887fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08c85011601612356565b8281528d828486010111156124875760008081fd5b828285018a8301376000928101890192909252508352509184019190840190612403565b9998505050505050505050565b600080600080600060a086880312156124d057600080fd5b6124d9866121ed565b945060208601359350604086013567ffffffffffffffff808211156124fd57600080fd5b61250989838a016123a5565b9450606088013591508082111561251f57600080fd5b61252b89838a016123a5565b9350608088013591508082111561254157600080fd5b5061254e888289016123a5565b9150509295509295909350565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b81810381811115611ced57611ced61255b565b8082028115828204841417611ced57611ced61255b565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000826125f2576125f26125b4565b500490565b80820180821115611ced57611ced61255b565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b803567ffffffffffffffff81168114611d2b57600080fd5b60006060828403121561266357600080fd5b6040516060810181811067ffffffffffffffff8211171561268657612686612327565b60405282356fffffffffffffffffffffffffffffffff811681146126a957600080fd5b81526126b760208401612639565b60208201526126c860408401612639565b60408201529392505050565b6000604082840312156126e657600080fd5b6040516040810181811067ffffffffffffffff8211171561270957612709612327565b60405282518152602083015164ffffffffff8116811461272857600080fd5b60208201529392505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036127655761276561255b565b5060010190565b60008261277b5761277b6125b4565b500690565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b60ff8281168282160390811115611ced57611ced61255b565b600181815b8085111561282157817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156128075761280761255b565b8085161561281457918102915b93841c93908002906127cd565b509250929050565b60008261283857506001611ced565b8161284557506000611ced565b816001811461285b576002811461286557612881565b6001915050611ced565b60ff8411156128765761287661255b565b50506001821b611ced565b5060208310610133831016604e8410600b84101617156128a4575081810a611ced565b6128ae83836127c8565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156128e0576128e061255b565b029392505050565b60006114ca838361282956fea164736f6c6343000814000a

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106100d45760003560e01c80638da5cb5b11610081578063cc275e8d1161005b578063cc275e8d146102a2578063e30c3978146102b5578063f2fde38b146102bd57600080fd5b80638da5cb5b14610177578063cbd006e31461017f578063cbf9fe5f1461018757600080fd5b8063715018a6116100b2578063715018a61461015457806379ba50971461015c5780637eff66661461016457600080fd5b80633c45b87c146100d9578063485cc9551461011e57806370a0823114610133575b600080fd5b6100f473c8418af6358ffdda74e09ca9cc3fe03ca6adc5b081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b61013161012c366004612211565b6102d0565b005b610146610141366004612244565b610519565b604051908152602001610115565b61013161064b565b61013161065f565b61013161017236600461225f565b6106df565b6100f4610901565b610146600281565b61025c610195366004612244565b60408051606080820183526000808352602080840182905292840181905273ffffffffffffffffffffffffffffffffffffffff9490941684527fc667da153497ef4116ec36eef54e190e9a94eda237a4c431c2176edb0ad62d4082529282902082519384018352546fffffffffffffffffffffffffffffffff8116845267ffffffffffffffff700100000000000000000000000000000000820481169285019290925278010000000000000000000000000000000000000000000000009004169082015290565b6040805182516fffffffffffffffffffffffffffffffff16815260208084015167ffffffffffffffff908116918301919091529282015190921690820152606001610115565b6101316102b03660046124b8565b610943565b6100f4610ecd565b6101316102cb366004612244565b610ef6565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff16159067ffffffffffffffff1660008115801561031b5750825b905060008267ffffffffffffffff1660011480156103385750303b155b905081158015610346575080155b1561037d576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84547fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000016600117855583156103de5784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff16680100000000000000001785555b7fc667da153497ef4116ec36eef54e190e9a94eda237a4c431c2176edb0ad62d41547fc667da153497ef4116ec36eef54e190e9a94eda237a4c431c2176edb0ad62d409073ffffffffffffffffffffffffffffffffffffffff1615801561045a575073ffffffffffffffffffffffffffffffffffffffff881615155b61046357600080fd5b6001810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8a161790556104ae87610fad565b5083156105105784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50505050505050565b73ffffffffffffffffffffffffffffffffffffffff811660009081527fc667da153497ef4116ec36eef54e190e9a94eda237a4c431c2176edb0ad62d4060208181526040808420815160608101835290546fffffffffffffffffffffffffffffffff8116825267ffffffffffffffff70010000000000000000000000000000000082048116948301859052780100000000000000000000000000000000000000000000000090910416918101919091529042101561064457630784ce0042826020015167ffffffffffffffff166105f0919061258a565b825161060f906fffffffffffffffffffffffffffffffff16600361259d565b610619919061259d565b61062391906125e3565b815161064191906fffffffffffffffffffffffffffffffff166125f7565b92505b5050919050565b610653611001565b61065d6000610fad565b565b3380610669610ecd565b73ffffffffffffffffffffffffffffffffffffffff16146106d3576040517f118cdaa700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024015b60405180910390fd5b6106dc81610fad565b50565b6106e7611001565b7fc667da153497ef4116ec36eef54e190e9a94eda237a4c431c2176edb0ad62d4083828114610742576040517fccab218c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b858110156105105760008787838181106107615761076161260a565b90506020020160208101906107769190612244565b9050600086868481811061078c5761078c61260a565b9050606002018036038101906107a29190612651565b73ffffffffffffffffffffffffffffffffffffffff83166000908152602087905260408120549192506fffffffffffffffffffffffffffffffff90911690036108f75773ffffffffffffffffffffffffffffffffffffffff8216600081815260208781526040918290208451815486840151878601516fffffffffffffffffffffffffffffffff9093167fffffffffffffffff000000000000000000000000000000000000000000000000909216821770010000000000000000000000000000000067ffffffffffffffff9283169081029190911777ffffffffffffffffffffffffffffffffffffffffffffffff1678010000000000000000000000000000000000000000000000009290941691820293909317909355845190815292830152918101919091527fd27db32ad6a2e889fcb35d08e573d9fd7c1bbed92246d3899fd73a80447900919060600160405180910390a25b5050600101610745565b6000807f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c1993005b5473ffffffffffffffffffffffffffffffffffffffff1692915050565b60007fc667da153497ef4116ec36eef54e190e9a94eda237a4c431c2176edb0ad62d4060018101546040517fbb141cf40000000000000000000000000000000000000000000000000000000081526004810188905291925060009173ffffffffffffffffffffffffffffffffffffffff9091169063bb141cf4906024016040805180830381865afa1580156109dc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a0091906126d4565b73ffffffffffffffffffffffffffffffffffffffff881660009081526020848152604090912054908201519192507801000000000000000000000000000000000000000000000000900467ffffffffffffffff1664ffffffffff90911611610aea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4c3156654658533a2043616e206f6e6c79207570646174652077697468206c6160448201527f74657220696e666f726d6174696f6e000000000000000000000000000000000060648201526084016106ca565b6000610b0f826000015173c8418af6358ffdda74e09ca9cc3fe03ca6adc5b088611059565b9050600060028973ffffffffffffffffffffffffffffffffffffffff16604051602001610b46929190918252602082015260400190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152828252805160209182012090830152016040516020818303038152906040528051906020012060001c90506000610bb083606001518360001b896111c9565b6020015190506000610bd38460600151846001610bcd91906125f7565b896111c9565b60200151905060008211610c43576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f4c3156654658533a20616d6f756e74206973207a65726f00000000000000000060448201526064016106ca565b6f7fffffffffffffffffffffffffffffff8210610cbc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4c3156654658533a20616d6f756e7420746f6f206c617267650000000000000060448201526064016106ca565b428111610d25576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4c3156654658533a206c6f636b2065787069726564000000000000000000000060448201526064016106ca565b630784ce00610d34428361258a565b1115610d9c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4c3156654658533a206c6f636b20746f6f206c6f6e670000000000000000000060448201526064016106ca565b73ffffffffffffffffffffffffffffffffffffffff8b16600081815260208881526040918290208054898301516fffffffffffffffffffffffffffffffff8881167fffffffffffffffff0000000000000000000000000000000000000000000000009093169290921770010000000000000000000000000000000067ffffffffffffffff89811682029290921777ffffffffffffffffffffffffffffffffffffffffffffffff811664ffffffffff909416780100000000000000000000000000000000000000000000000081029485179687905588519186169590941694909417845290930490921692810192909252918101919091527fd27db32ad6a2e889fcb35d08e573d9fd7c1bbed92246d3899fd73a80447900919060600160405180910390a25050505050505050505050565b6000807f237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c00610926565b610efe611001565b7f237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c0080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081178255610f67610901565b73ffffffffffffffffffffffffffffffffffffffff167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a35050565b7f237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c0080547fffffffffffffffffffffffff0000000000000000000000000000000000000000168155610ffd826112c4565b5050565b3361100a610901565b73ffffffffffffffffffffffffffffffffffffffff161461065d576040517f118cdaa70000000000000000000000000000000000000000000000000000000081523360048201526024016106ca565b6040805160a0810182526000808252602082018190529181018290526060810182905260808101919091526000825167ffffffffffffffff8111156110a0576110a0612327565b6040519080825280602002602001820160405280156110e557816020015b60408051808201909152600080825260208201528152602001906001900390816110be5790505b50905060005b835181101561116c5761113e8482815181106111095761110961260a565b602002602001015160408051808201825260008082526020918201528151808301909252825182529182019181019190915290565b8282815181106111505761115061260a565b60200260200101819052508061116590612734565b90506110eb565b506040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606086901b1660208201526111c09060340160405160208183030381529060405280519060200120868361135a565b95945050505050565b60408051808201909152600080825260208201526000825167ffffffffffffffff8111156111f9576111f9612327565b60405190808252806020026020018201604052801561123e57816020015b60408051808201909152600080825260208201528152602001906001900390816112175790505b50905060005b8351811015611290576112628482815181106111095761110961260a565b8282815181106112745761127461260a565b60200260200101819052508061128990612734565b9050611244565b506111c0846040516020016112a791815260200190565b6040516020818303038152906040528051906020012086836114d1565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080547fffffffffffffffffffffffff0000000000000000000000000000000000000000811673ffffffffffffffffffffffffffffffffffffffff848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915260006113b3848660405160200161139e91815260200190565b6040516020818303038152906040528561155e565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915290915081516000036113f35791506114ca9050565b600061142e6114298460408051808201825260008082526020918201528151808301909252825182529182019181019190915290565b61199a565b9050805160041461143e57600080fd5b6001825280516114669082906000906114595761145961260a565b6020026020010151611ab0565b6020830152805161148490829060019081106114595761145961260a565b604083015280516114a290829060029081106114595761145961260a565b606083015280516114c090829060039081106114595761145961260a565b6080830152509150505b9392505050565b604080518082019091526000808252602082015260006114fe848660405160200161139e91815260200190565b60408051808201909152600080825260208201529091508151156111c0576001815260408051808201825260008082526020918201528151808301909252835182528084019082015261155090611ab0565b602082015295945050505050565b6060600061156d846000611afe565b90506000806060611591604051806040016040528060008152602001600081525090565b86516000036115e2577f56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b42189146115c657600080fd5b505060408051600081526020810190915293506114ca92505050565b60005b875181101561198d5780158015611624575061162088828151811061160c5761160c61260a565b602002602001015160208101519051902090565b8a14155b1561162e57600080fd5b801580159061165e575061165a88828151811061164d5761164d61260a565b6020026020010151611cd4565b8414155b1561166857600080fd5b61168a88828151811061167d5761167d61260a565b602002602001015161199a565b9250825160020361183657600060606116c46116bf866000815181106116b2576116b261260a565b6020026020010151611d30565b611dae565b909250905060006116d6888a84611e49565b90506116e281896125f7565b975081518110156117455760018b516116fb919061258a565b84101561170757600080fd5b60005b6040519080825280601f01601f191660200182016040528015611734576020820181803683370190505b5099505050505050505050506114ca565b82156117ab5760018b51611759919061258a565b84101561176557600080fd5b885188101561177557600061170a565b856001815181106117885761178861260a565b6020026020010151945061179b85611d30565b99505050505050505050506114ca565b60018b516117b9919061258a565b84036117c457600080fd5b6117e7866001815181106117da576117da61260a565b6020026020010151611f04565b6118155761180e866001815181106118015761180161260a565b6020026020010151611f3f565b965061182e565b61182b8660018151811061160c5761160c61260a565b96505b50505061197b565b825160110361197b578551851461193f57600086868151811061185b5761185b61260a565b016020015160f81c90506118706001876125f7565b955060108160ff161061188257600080fd5b6118a7848260ff168151811061189a5761189a61260a565b6020026020010151611f57565b156118e357600189516118ba919061258a565b82146118c557600080fd5b505060408051600081526020810190915295506114ca945050505050565b6118fb848260ff16815181106117da576117da61260a565b61191e57611917848260ff16815181106118015761180161260a565b9450611939565b611936848260ff168151811061160c5761160c61260a565b94505b5061197b565b6001885161194d919061258a565b811461195857600080fd5b61196e836010815181106116b2576116b261260a565b96505050505050506114ca565b8061198581612734565b9150506115e5565b5050505050509392505050565b60606119a582611f04565b6119ae57600080fd5b60006119b983611f7a565b905060008167ffffffffffffffff8111156119d6576119d6612327565b604051908082528060200260200182016040528015611a1b57816020015b60408051808201909152600080825260208201528152602001906001900390816119f45790505b5090506000611a2d8560200151611fff565b8560200151611a3c91906125f7565b90506000805b84811015611aa557611a538361207a565b9150604051806040016040528083815260200184815250848281518110611a7c57611a7c61260a565b6020908102919091010152611a9182846125f7565b925080611a9d81612734565b915050611a42565b509195945050505050565b805160009015801590611ac557508151602110155b611ace57600080fd5b600080611ada84612123565b815191935091506020821015611af65760208290036101000a90045b949350505050565b60606000835111611b0e57600080fd5b600083516002611b1e919061259d565b905080831115611b2d57600080fd5b611b37838261258a565b90508067ffffffffffffffff811115611b5257611b52612327565b6040519080825280601f01601f191660200182016040528015611b7c576020820181803683370190505b5091506000835b611b8d83866125f7565b811015611cbb57611b9f60028261276c565b600003611c2357600486611bb46002846125e3565b81518110611bc457611bc461260a565b602001015160f81c60f81b60f81c60ff16901c600f1660f81b848381518110611bef57611bef61260a565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350611c9c565b600086611c316002846125e3565b81518110611c4157611c4161260a565b602001015160f81c60f81b60f81c60ff16901c600f1660f81b848381518110611c6c57611c6c61260a565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053505b611ca76001836125f7565b9150611cb46001826125f7565b9050611b83565b5082518114611ccc57611ccc612780565b505092915050565b6000602082600001511015611cf3576020820151825190205b92915050565b602082015182519020604051602001611d0e91815260200190565b604051602081830303815290604052805190602001209050919050565b919050565b8051606090611d3e57600080fd5b600080611d4a84612123565b9150915060008167ffffffffffffffff811115611d6957611d69612327565b6040519080825280601f01601f191660200182016040528015611d93576020820181803683370190505b50905060208101611da584828561216a565b50949350505050565b600060606000835111611dc057600080fd5b6000600484600081518110611dd757611dd761260a565b60209101015160f81c901c600f1690506000818103611dfc5750600092506002611e33565b81600103611e105750600092506001611e33565b81600203611e245750600192506002611e33565b816003036100d4575060019250825b83611e3e8683611afe565b935093505050915091565b6000805b8351611e5986836125f7565b108015611e665750825181105b15611af657828181518110611e7d57611e7d61260a565b01602001517fff000000000000000000000000000000000000000000000000000000000000001684611eaf87846125f7565b81518110611ebf57611ebf61260a565b01602001517fff000000000000000000000000000000000000000000000000000000000000001614611ef25790506114ca565b80611efc81612734565b915050611e4d565b80516000908103611f1757506000919050565b6020820151805160001a9060c0821015611f35575060009392505050565b5060019392505050565b6000806000611f4d84612123565b9020949350505050565b8051600090600114611f6b57506000919050565b50602001515160001a60801490565b80516000908103611f8d57506000919050565b600080611f9d8460200151611fff565b8460200151611fac91906125f7565b9050600084600001518560200151611fc491906125f7565b90505b80821015611ff657611fd88261207a565b611fe290836125f7565b915082611fee81612734565b935050611fc7565b50909392505050565b8051600090811a60808110156120185750600092915050565b60b8811080612033575060c08110801590612033575060f881105b156120415750600192915050565b60c081101561206e57612056600160b86127af565b6120639060ff168261258a565b6114ca9060016125f7565b612056600160f86127af565b80516000908190811a6080811015612095576001915061211c565b60b88110156120bb576120a960808261258a565b6120b49060016125f7565b915061211c565b60c08110156120e85760b78103600185019450806020036101000a8551046001820181019350505061211c565b60f88110156120fc576120a960c08261258a565b60f78103600185019450806020036101000a855104600182018101935050505b5092915050565b60008060006121358460200151611fff565b9050600081856020015161214991906125f7565b9050600082866000015161215d919061258a565b9196919550909350505050565b8060000361217757505050565b602081106121af578251825261218e6020846125f7565b925061219b6020836125f7565b91506121a860208261258a565b9050612177565b80156121e857600060016121c483602061258a565b6121d0906101006128e8565b6121da919061258a565b845184518216911916178352505b505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611d2b57600080fd5b6000806040838503121561222457600080fd5b61222d836121ed565b915061223b602084016121ed565b90509250929050565b60006020828403121561225657600080fd5b6114ca826121ed565b6000806000806040858703121561227557600080fd5b843567ffffffffffffffff8082111561228d57600080fd5b818701915087601f8301126122a157600080fd5b8135818111156122b057600080fd5b8860208260051b85010111156122c557600080fd5b6020928301965094509086013590808211156122e057600080fd5b818701915087601f8301126122f457600080fd5b81358181111561230357600080fd5b88602060608302850101111561231857600080fd5b95989497505060200194505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561239d5761239d612327565b604052919050565b6000601f83818401126123b757600080fd5b8235602067ffffffffffffffff808311156123d4576123d4612327565b8260051b6123e3838201612356565b93845286810183019383810190898611156123fd57600080fd5b84890192505b858310156124ab5782358481111561241b5760008081fd5b8901603f81018b1361242d5760008081fd5b8581013560408682111561244357612443612327565b612472887fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08c85011601612356565b8281528d828486010111156124875760008081fd5b828285018a8301376000928101890192909252508352509184019190840190612403565b9998505050505050505050565b600080600080600060a086880312156124d057600080fd5b6124d9866121ed565b945060208601359350604086013567ffffffffffffffff808211156124fd57600080fd5b61250989838a016123a5565b9450606088013591508082111561251f57600080fd5b61252b89838a016123a5565b9350608088013591508082111561254157600080fd5b5061254e888289016123a5565b9150509295509295909350565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b81810381811115611ced57611ced61255b565b8082028115828204841417611ced57611ced61255b565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000826125f2576125f26125b4565b500490565b80820180821115611ced57611ced61255b565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b803567ffffffffffffffff81168114611d2b57600080fd5b60006060828403121561266357600080fd5b6040516060810181811067ffffffffffffffff8211171561268657612686612327565b60405282356fffffffffffffffffffffffffffffffff811681146126a957600080fd5b81526126b760208401612639565b60208201526126c860408401612639565b60408201529392505050565b6000604082840312156126e657600080fd5b6040516040810181811067ffffffffffffffff8211171561270957612709612327565b60405282518152602083015164ffffffffff8116811461272857600080fd5b60208201529392505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036127655761276561255b565b5060010190565b60008261277b5761277b6125b4565b500690565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b60ff8281168282160390811115611ced57611ced61255b565b600181815b8085111561282157817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156128075761280761255b565b8085161561281457918102915b93841c93908002906127cd565b509250929050565b60008261283857506001611ced565b8161284557506000611ced565b816001811461285b576002811461286557612881565b6001915050611ced565b60ff8411156128765761287661255b565b50506001821b611ced565b5060208310610133831016604e8410600b84101617156128a4575081810a611ced565b6128ae83836127c8565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156128e0576128e061255b565b029392505050565b60006114ca838361282956fea164736f6c6343000814000a

Deployed Bytecode Sourcemap

1309:6851:5:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1518:81;;1557:42;1518:81;;;;;190:42:11;178:55;;;160:74;;148:2;133:18;1518:81:5;;;;;;;;3107:360;;;;;;:::i;:::-;;:::i;:::-;;6629:442;;;;;;:::i;:::-;;:::i;:::-;;;1048:25:11;;;1036:2;1021:18;6629:442:5;902:177:11;3155:101:1;;;:::i;2774:229:0:-;;;:::i;7270:859:5:-;;;;;;:::i;:::-;;:::i;2441:144:1:-;;;:::i;1430:45:5:-;;1474:1;1430:45;;2428:164;;;;;;:::i;:::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;2568:17:5;;;;;;;2352:18;2568:17;;;;;;2561:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2428:164;;;;;2460:13:11;;2475:34;2456:54;2438:73;;2558:4;2546:17;;;2540:24;2583:18;2639:21;;;2617:20;;;2610:51;;;;2709:17;;;2703:24;2699:33;;;2677:20;;;2670:63;2426:2;2411:18;2428:164:5;2230:509:11;4114:2308:5;;;;;;:::i;:::-;;:::i;1680:168:0:-;;;:::i;2041:247::-;;;;;;:::i;:::-;;:::i;3107:360:5:-;8870:21:2;4302:15;;;;;;;4301:16;;4348:14;;4158:30;4726:16;;:34;;;;;4746:14;4726:34;4706:54;;4770:17;4790:11;:16;;4805:1;4790:16;:50;;;;-1:-1:-1;4818:4:2;4810:25;:30;4790:50;4770:70;;4856:12;4855:13;:30;;;;;4873:12;4872:13;4855:30;4851:91;;;4908:23;;;;;;;;;;;;;;4851:91;4951:18;;;;4968:1;4951:18;;;4979:67;;;;5013:22;;;;;;;;4979:67;3293:17:5;;2352:18;;3285:40:::1;3293:17;3285:40:::0;:74;::::1;;;-1:-1:-1::0;3329:30:5::1;::::0;::::1;::::0;::::1;3285:74;3277:83;;;::::0;::::1;;3370:17;::::0;::::1;:54:::0;;;::::1;;::::0;::::1;;::::0;;3434:26:::1;3453:6:::0;3434:18:::1;:26::i;:::-;3190:277;5070:14:2::0;5066:101;;;5100:23;;;;;;5142:14;;-1:-1:-1;6052:50:11;;5142:14:2;;6040:2:11;6025:18;5142:14:2;;;;;;;5066:101;4092:1081;;;;;3107:360:5;;:::o;6629:442::-;6800:18;;;6689:16;6800:18;;;2352;6800;;;;;;;;6762:56;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6853:15;-1:-1:-1;6828:237:5;;;1680:16;7011:15;6990:14;:18;;;:36;;;;;;:::i;:::-;6960:21;;6952:34;;:30;;6985:1;6952:34;:::i;:::-;:75;;;;:::i;:::-;6951:103;;;;:::i;:::-;6911:21;;:143;;;;;;:::i;:::-;6884:170;;6828:237;6707:364;;6629:442;;;:::o;3155:101:1:-;2334:13;:11;:13::i;:::-;3219:30:::1;3246:1;3219:18;:30::i;:::-;3155:101::o:0;2774:229:0:-;966:10:3;;2869:14:0;:12;:14::i;:::-;:24;;;2865:96;;2916:34;;;;;190:42:11;178:55;;2916:34:0;;;160:74:11;133:18;;2916:34:0;;;;;;;;2865:96;2970:26;2989:6;2970:18;:26::i;:::-;2816:187;2774:229::o;7270:859:5:-;2334:13:1;:11;:13::i;:::-;2352:18:5;7481:10;7512:32;;::::1;7508:61;;7553:16;;;;;;;;;;;;;;7508:61;7585:9;7580:543;7600:21:::0;;::::1;7580:543;;;7639:16;7658:10;;7669:1;7658:13;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;7639:32;;7685:35;7723:15;;7739:1;7723:18;;;;;;;:::i;:::-;;;;;;7685:56;;;;;;;;;;:::i;:::-;7834:18;::::0;::::1;:8;:18:::0;;;::::1;::::0;;;;;;:25;7685:56;;-1:-1:-1;7834:25:5::1;::::0;;::::1;:30:::0;;7830:223:::1;;7884:18;::::0;::::1;:8;:18:::0;;;::::1;::::0;;;;;;;;:35;;;;;;::::1;::::0;;;::::1;::::0;::::1;::::0;;::::1;::::0;;;;;;;::::1;::::0;;::::1;::::0;;::::1;::::0;;;::::1;::::0;::::1;::::0;;;;::::1;::::0;;::::1;::::0;;;::::1;::::0;;;7942:96;;8327:66:11;;;8446:18;;;8439:43;8498:18;;;8491:43;;;;7942:96:5::1;::::0;8315:2:11;8300:18;7942:96:5::1;;;;;;;7830:223;-1:-1:-1::0;;8095:3:5::1;;7580:543;;2441:144:1::0;2487:7;;1313:22;2533:20;2570:8;;;;2441:144;-1:-1:-1;;2441:144:1:o;4114:2308:5:-;4331:20;2352:18;4423:17;;;;:44;;;;;;;;1048:25:11;;;4423:17:5;;-1:-1:-1;4376:44:5;;4423:17;;;;;:30;;1021:18:11;;4423:44:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;4521:18;;;:8;:18;;;;;;;;;;;:33;4498:20;;;;;;-1:-1:-1;4521:33:5;;;;;4498:56;;;;;4477:150;;;;;;;9354:2:11;4477:150:5;;;9336:21:11;9393:2;9373:18;;;9366:30;9432:34;9412:18;;;9405:62;9503:17;9483:18;;;9476:45;9538:19;;4477:150:5;9152:411:11;4477:150:5;4638:36;4677:179;4740:10;:24;;;1557:42;4832:13;4677:33;:179::i;:::-;4638:218;;4923:13;1474:1;5049:8;5033:26;;4997:63;;;;;;;;9725:19:11;;;9769:2;9760:12;;9753:28;9806:2;9797:12;;9568:247;4997:63:5;;;;;;;;;;;;;;4987:74;;4997:63;4987:74;;;;4970:92;;;9949:19:11;9984:12;4970:92:5;;;;;;;;;;;;4960:103;;;;;;4939:134;;4923:150;;5124:15;5163:230;5258:12;:24;;;5318:5;5310:14;;5360;5163:55;:230::i;:::-;:253;;;5124:302;;5474:12;5510:234;5605:12;:24;;;5665:5;5673:1;5665:9;;;;:::i;:::-;5711:14;5510:55;:234::i;:::-;:257;;;5474:303;;5831:1;5821:7;:11;5813:47;;;;;;;10209:2:11;5813:47:5;;;10191:21:11;10248:2;10228:18;;;10221:30;10287:25;10267:18;;;10260:53;10330:18;;5813:47:5;10007:347:11;5813:47:5;5896:16;5878:35;;5870:73;;;;;;;10561:2:11;5870:73:5;;;10543:21:11;10600:2;10580:18;;;10573:30;10639:27;10619:18;;;10612:55;10684:18;;5870:73:5;10359:349:11;5870:73:5;5968:15;5961:4;:22;5953:56;;;;;;;10915:2:11;5953:56:5;;;10897:21:11;10954:2;10934:18;;;10927:30;10993:23;10973:18;;;10966:51;11034:18;;5953:56:5;10713:345:11;5953:56:5;1680:16;6027:22;6034:15;6027:4;:22;:::i;:::-;:33;;6019:68;;;;;;;11265:2:11;6019:68:5;;;11247:21:11;11304:2;11284:18;;;11277:30;11343:24;11323:18;;;11316:52;11385:18;;6019:68:5;11063:346:11;6019:68:5;6124:18;;;:8;:18;;;;;;;;;;;;:44;;6261:20;;;;6124:44;;;;6178:37;;;;;;;;;;;;;;;;;;;6225:56;;;;;;;;;;;;;;;;;6320:95;;6343:25;;;;;;;;;;;11612:66:11;;6370:22:5;;;;;;11694:18:11;;;11687:59;;;;11762:18;;;11755:53;;;;6320:95:5;;11600:2:11;11585:18;6320:95:5;;;;;;;4321:2101;;;;;;4114:2308;;;;;:::o;1680:168:0:-;1733:7;;1318:27;1784:25;1187:174;2041:247;2334:13:1;:11;:13::i;:::-;1318:27:0;2197:26;;;::::1;;::::0;::::1;::::0;;::::1;::::0;;2263:7:::1;:5;:7::i;:::-;2238:43;;;;;;;;;;;;2120:168;2041:247:::0;:::o;2472:222::-;1318:27;2621:22;;;;;;2653:34;2678:8;2653:24;:34::i;:::-;2544:150;2472:222;:::o;2658:162:1:-;966:10:3;2717:7:1;:5;:7::i;:::-;:23;;;2713:101;;2763:40;;;;;966:10:3;2763:40:1;;;160:74:11;133:18;;2763:40:1;14:226:11;1782:645:9;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1982:42:9;2051:12;:19;2027:44;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;;;;;;;2027:44:9;;;;;;;;;;;;;;;;1982:89;;2086:9;2081:123;2105:12;:19;2101:1;:23;2081:123;;;2166:27;:12;2179:1;2166:15;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;;;;;;;;;;;;;1699:28:4;;;;;;;;1707:11;;1699:28;;1657:15;;;1699:28;;;;;;;;1513:221;2166:27:9;2145:15;2161:1;2145:18;;;;;;;;:::i;:::-;;;;;;:48;;;;2126:3;;;;:::i;:::-;;;2081:123;;;-1:-1:-1;2298:30:9;;12181:66:11;12168:2;12164:15;;;12160:88;2298:30:9;;;12148:101:11;2227:193:9;;12265:12:11;;2298:30:9;;;;;;;;;;;;2288:41;;;;;;2359:13;2394:15;2227:32;:193::i;:::-;2213:207;1782:645;-1:-1:-1;;;;;1782:645:9:o;2764:637::-;-1:-1:-1;;;;;;;;;;;;;;;;;2963:42:9;3032:12;:19;3008:44;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;;;;;;;3008:44:9;;;;;;;;;;;;;;;;2963:89;;3067:9;3062:123;3086:12;:19;3082:1;:23;3062:123;;;3147:27;:12;3160:1;3147:15;;;;;;;;:::i;:27::-;3126:15;3142:1;3126:18;;;;;;;;:::i;:::-;;;;;;:48;;;;3107:3;;;;:::i;:::-;;;3062:123;;;;3206:188;3293:4;3276:22;;;;;;9949:19:11;;9993:2;9984:12;;9820:182;3276:22:9;;;;;;;;;;;;;3266:33;;;;;;3331:15;3368;3206:34;:188::i;3774:248:1:-;1313:22;3923:8;;3941:19;;;3923:8;3941:19;;;;;;;;3975:40;;3923:8;;;;;3975:40;;3847:24;;3975:40;3837:185;;3774:248;:::o;2565:930:10:-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2798:25:10;2826:147;2885:14;2930:12;2913:30;;;;;;9949:19:11;;9993:2;9984:12;;9820:182;2913:30:10;;;;;;;;;;;;;2957:6;2826:45;:147::i;:::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2798:175:10;;-1:-1:-1;3021:12:10;:19;3044:1;3021:24;3017:69;;3068:7;-1:-1:-1;3061:14:10;;-1:-1:-1;3061:14:10;3017:69;3096:37;3136:33;:24;:12;-1:-1:-1;;;;;;;;;;;;;;;;;1699:28:4;;;;;;;;1707:11;;1699:28;;1657:15;;;1699:28;;;;;;;;1513:221;3136:24:10;:31;:33::i;:::-;3096:73;;3187:10;:17;3208:1;3187:22;3179:31;;;;;;3238:4;3221:21;;3268:13;;:22;;:10;;3221:14;;3268:13;;;;:::i;:::-;;;;;;;:20;:22::i;:::-;3252:13;;;:38;3318:13;;:22;;:10;;3329:1;;3318:13;;;;;;:::i;:22::-;3300:15;;;:40;3380:13;;:22;;:10;;3391:1;;3380:13;;;;;;:::i;:22::-;3350:19;;;:53;3440:13;;:22;;:10;;3451:1;;3440:13;;;;;;:::i;:22::-;3413:16;;;:50;-1:-1:-1;3413:7:10;-1:-1:-1;;2565:930:10;;;;;;:::o;3748:581::-;-1:-1:-1;;;;;;;;;;;;;;;;;3944:26:10;3973:146;4032:16;4079:9;4062:27;;;;;;9949:19:11;;9993:2;9984:12;;9820:182;3973:146:10;-1:-1:-1;;;;;;;;;;;;;;;;;3944:175:10;;-1:-1:-1;4167:20:10;;:25;4163:137;;4223:4;4208:19;;-1:-1:-1;;;;;;;;;;;;;;;;;1699:28:4;;;;;;;;1707:11;;1699:28;;1657:15;;;1699:28;;;;4255:34:10;;:32;:34::i;:::-;4241:11;;;:48;4317:5;3748:581;-1:-1:-1;;;;;3748:581:10:o;1267:5475:8:-;1418:18;1448:19;1470:23;1485:4;1491:1;1470:14;:23::i;:::-;1448:45;;1503:20;1538;1568:31;1610:33;-1:-1:-1;;;;;;;;;;;;;;;;;;;1610:33:8;1658:5;:12;1674:1;1658:17;1654:223;;1766:66;1754:78;;1746:87;;;;;;-1:-1:-1;;1854:12:8;;;1864:1;1854:12;;;;;;;;;-1:-1:-1;1847:19:8;;-1:-1:-1;;;1847:19:8;1654:223;1945:9;1940:4796;1964:5;:12;1960:1;:16;1940:4796;;;2238:6;;:50;;;;;2260:28;:5;2266:1;2260:8;;;;;;;;:::i;:::-;;;;;;;4156:11:4;;;;4191:8;;4266:19;;;4052:272;2260:28:8;2248:8;:40;;2238:50;2234:97;;;2308:8;;;2234:97;2445:6;;;;;:48;;;2471:22;2484:5;2490:1;2484:8;;;;;;;;:::i;:::-;;;;;;;2471:12;:22::i;:::-;2455:12;:38;;2445:48;2441:95;;;2513:8;;;2441:95;2662:17;:5;2668:1;2662:8;;;;;;;;:::i;:::-;;;;;;;:15;:17::i;:::-;2655:24;;2698:4;:11;2713:1;2698:16;2694:4032;;2777:11;2806:20;2864:47;2893:17;:4;2898:1;2893:7;;;;;;;;:::i;:::-;;;;;;;:15;:17::i;:::-;2864:28;:47::i;:::-;2844:67;;-1:-1:-1;2844:67:8;-1:-1:-1;2930:20:8;2953:50;2973:12;2987:6;2844:67;2953:19;:50::i;:::-;2930:73;-1:-1:-1;3021:28:8;2930:73;3021:28;;:::i;:::-;;;3087:7;:14;3072:12;:29;3068:994;;;3876:1;3861:5;:12;:16;;;;:::i;:::-;3857:1;:20;3853:149;;;3971:8;;;3853:149;4041:1;4031:12;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;4031:12:8;;4024:19;;;;;;;;;;;;;3068:994;4084:6;4080:1175;;;4173:1;4158:5;:12;:16;;;;:::i;:::-;4154:1;:20;4150:144;;;4263:8;;;4150:144;4335:6;:13;4320:12;:28;4316:102;;;4393:1;4383:12;;4316:102;4451:4;4456:1;4451:7;;;;;;;;:::i;:::-;;;;;;;4440:18;;4487;:8;:16;:18::i;:::-;4480:25;;;;;;;;;;;;;4080:1175;4645:1;4630:5;:12;:16;;;;:::i;:::-;4625:1;:21;4621:138;;4728:8;;;4621:138;4786:16;:4;4791:1;4786:7;;;;;;;;:::i;:::-;;;;;;;:14;:16::i;:::-;4781:456;;4973:26;:4;4978:1;4973:7;;;;;;;;:::i;:::-;;;;;;;:24;:26::i;:::-;4958:41;;4781:456;;;5187:27;:4;5192:1;5187:7;;;;;;;;:::i;:27::-;5172:42;;4781:456;2716:2553;;;2694:4032;;;5279:4;:11;5294:2;5279:17;5275:1451;;5368:6;:13;5352:12;:29;5348:1364;;5495:12;5516:6;5523:12;5516:20;;;;;;;;:::i;:::-;;;;;;;;-1:-1:-1;5559:17:8;5575:1;5559:17;;:::i;:::-;;;5612:2;5602:6;:12;;;5598:146;;5713:8;;;5598:146;5770:34;5791:4;5796:6;5791:12;;;;;;;;;;:::i;:::-;;;;;;;5770:20;:34::i;:::-;5766:556;;;5890:1;5875:5;:12;:16;;;;:::i;:::-;5870:1;:21;5866:157;;5988:8;;;5866:157;-1:-1:-1;;6056:12:8;;;6066:1;6056:12;;;;;;;;;-1:-1:-1;6049:19:8;;-1:-1:-1;;;;;6049:19:8;5766:556;6102:21;:4;6107:6;6102:12;;;;;;;;;;:::i;:21::-;6097:225;;6166:31;:4;6171:6;6166:12;;;;;;;;;;:::i;:31::-;6151:46;;6097:225;;;6267:32;:4;6272:6;6267:12;;;;;;;;;;:::i;:32::-;6252:47;;6097:225;5383:957;5348:1364;;;6535:1;6520:5;:12;:16;;;;:::i;:::-;6515:1;:21;6511:135;;6615:8;;;6511:135;6675:18;:4;6680:2;6675:8;;;;;;;;:::i;:18::-;6668:25;;;;;;;;;;5348:1364;1978:3;;;;:::i;:::-;;;;1940:4796;;;;1438:5304;;;;;1267:5475;;;;;:::o;2946:519:4:-;3006:16;3042:12;3049:4;3042:6;:12::i;:::-;3034:21;;;;;;3066:13;3082:14;3091:4;3082:8;:14::i;:::-;3066:30;;3106:23;3146:5;3132:20;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;;;;;;;3132:20:4;;;;;;;;;;;;;;;;3106:46;;3163:14;3194:27;3209:4;:11;;;3194:14;:27::i;:::-;3180:4;:11;;;:41;;;;:::i;:::-;3163:58;-1:-1:-1;3231:15:4;;3256:179;3280:5;3276:1;:9;3256:179;;;3316:19;3328:6;3316:11;:19::i;:::-;3306:29;;3361:24;;;;;;;;3369:7;3361:24;;;;3378:6;3361:24;;;3349:6;3356:1;3349:9;;;;;;;;:::i;:::-;;;;;;;;;;:36;3408:16;3417:7;3408:6;:16;:::i;:::-;3399:25;-1:-1:-1;3287:3:4;;;;:::i;:::-;;;;3256:179;;;-1:-1:-1;3452:6:4;;2946:519;-1:-1:-1;;;;;2946:519:4:o;6049:467::-;6136:8;;6109:7;;6136:12;;;;:30;;-1:-1:-1;6152:8:4;;6164:2;-1:-1:-1;6152:14:4;6136:30;6128:39;;;;;;6179:14;6195:11;6210:21;6226:4;6210:15;:21::i;:::-;6299:13;;6178:53;;-1:-1:-1;6178:53:4;-1:-1:-1;6395:2:4;6387:11;;6384:92;;;6452:2;6448:12;;;6443:3;6439:22;6427:35;;6384:92;6503:6;6049:467;-1:-1:-1;;;;6049:467:4:o;8723:747:8:-;8812:20;8869:1;8852:7;:14;:18;8844:27;;;;;;8882:14;8899:7;:14;8916:1;8899:18;;;;:::i;:::-;8882:35;;8950:6;8935:11;:21;;8927:30;;;;;;8967:21;8977:11;8967:21;;:::i;:::-;;;9019:6;9009:17;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;9009:17:8;-1:-1:-1;8999:27:8;-1:-1:-1;9036:21:8;9089:11;9072:342;9106:20;9120:6;9106:11;:20;:::i;:::-;9102:1;:24;9072:342;;;9154:5;9158:1;9154;:5;:::i;:::-;9163:1;9154:10;9150:222;;9242:1;9223:7;9231:5;9235:1;9231;:5;:::i;:::-;9223:14;;;;;;;;:::i;:::-;;;;;;;;;9217:21;;:26;;;;9247:3;9216:34;9209:42;;9184:7;9192:13;9184:22;;;;;;;;:::i;:::-;;;;:67;;;;;;;;;;;9150:222;;;9348:1;9329:7;9337:5;9341:1;9337;:5;:::i;:::-;9329:14;;;;;;;;:::i;:::-;;;;;;;;;9323:21;;:26;;;;9353:3;9322:34;9315:42;;9290:7;9298:13;9290:22;;;;;;;;:::i;:::-;;;;:67;;;;;;;;;;;9150:222;9385:18;9402:1;9385:18;;:::i;:::-;;-1:-1:-1;9128:6:8;9133:1;9128:6;;:::i;:::-;;;9072:342;;;;9448:7;:14;9431:13;:31;9424:39;;;;:::i;:::-;8834:636;;8723:747;;;;:::o;7307:266::-;7382:7;7416:2;7405:4;:8;;;:13;7401:166;;;4156:11:4;;;;4191:8;;4266:19;;7441:24:8;7434:31;7307:266;-1:-1:-1;;7307:266:8:o;7401:166::-;4156:11:4;;;;4191:8;;4266:19;;7513:42:8;;;;;;9949:19:11;;9993:2;9984:12;;9820:182;7513:42:8;;;;;;;;;;;;;7503:53;;;;;;7496:60;;7307:266;;;:::o;7401:166::-;7307:266;;;:::o;6857:379:4:-;6950:8;;6918:12;;6942:21;;;;;;6975:14;6991:11;7006:21;7022:4;7006:15;:21::i;:::-;6974:53;;;;7037:19;7069:3;7059:14;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;7059:14:4;-1:-1:-1;7037:36:4;-1:-1:-1;7147:4:4;7143:17;;7180:26;7185:6;7143:17;7202:3;7180:4;:26::i;:::-;-1:-1:-1;7223:6:4;6857:379;-1:-1:-1;;;;6857:379:4:o;7920:797:8:-;8016:11;8029:20;8086:1;8069:7;:14;:18;8061:27;;;;;;8098:20;8143:1;8128:7;8136:1;8128:10;;;;;;;;:::i;:::-;;;;;;;;8122:22;;8148:3;8121:30;;-1:-1:-1;8161:19:8;8194:17;;;8190:458;;-1:-1:-1;8265:5:8;;-1:-1:-1;8241:1:8;8190:458;;;8291:12;8307:1;8291:17;8287:361;;-1:-1:-1;8362:5:8;;-1:-1:-1;8338:1:8;8287:361;;;8388:12;8404:1;8388:17;8384:264;;-1:-1:-1;8459:4:8;;-1:-1:-1;8435:1:8;8384:264;;;8484:12;8500:1;8484:17;8480:168;;-1:-1:-1;8531:1:8;;-1:-1:-1;8531:1:8;8480:168;8665:6;8673:36;8688:7;8697:11;8673:14;:36::i;:::-;8657:53;;;;;;7920:797;;;:::o;9476:321::-;9579:7;;9617:156;9644:9;;9629:12;9633:8;9629:1;:12;:::i;:::-;:24;:41;;;;;9661:2;:9;9657:1;:13;9629:41;9617:156;;;9715:2;9718:1;9715:5;;;;;;;;:::i;:::-;;;;;;;9695:2;9698:12;9702:8;9698:1;:12;:::i;:::-;9695:16;;;;;;;;:::i;:::-;;;;;;;:25;9691:72;;9747:1;-1:-1:-1;9740:8:8;;9691:72;9672:3;;;;:::i;:::-;;;;9617:156;;3569:321:4;3649:8;;3629:4;;3649:13;;3645:31;;-1:-1:-1;3671:5:4;;3569:321;-1:-1:-1;3569:321:4:o;3645:31::-;3725:11;;;;3786:13;;3687:11;3778:22;;328:4;3824:24;;3820:42;;;-1:-1:-1;3857:5:4;;3569:321;-1:-1:-1;;;3569:321:4:o;3820:42::-;-1:-1:-1;3879:4:4;;3569:321;-1:-1:-1;;;3569:321:4:o;4482:270::-;4552:7;4572:14;4588:11;4603:21;4619:4;4603:15;:21::i;:::-;4691:22;;;4482:270;-1:-1:-1;;;;4482:270:4:o;7579:335:8:-;7682:8;;7662:4;;7694:1;7682:13;7678:56;;-1:-1:-1;7718:5:8;;7579:335;-1:-1:-1;7579:335:8:o;7678:56::-;-1:-1:-1;7777:11:8;;;7834:13;7743:7;7826:22;7879:4;7874:9;;7579:335::o;7344:424:4:-;7428:8;;7405:7;;7428:13;;7424:27;;-1:-1:-1;7450:1:4;;7344:424;-1:-1:-1;7344:424:4:o;7424:27::-;7462:13;7489:15;7521:27;7536:4;:11;;;7521:14;:27::i;:::-;7507:4;:11;;;:41;;;;:::i;:::-;7489:59;;7558:14;7589:4;:8;;;7575:4;:11;;;:22;;;;:::i;:::-;7558:39;;7607:132;7624:6;7614:7;:16;7607:132;;;7666:20;7678:7;7666:11;:20::i;:::-;7656:30;;:7;:30;:::i;:::-;7646:40;-1:-1:-1;7721:7:4;;;;:::i;:::-;;;;7607:132;;;-1:-1:-1;7756:5:4;;7344:424;-1:-1:-1;;;7344:424:4:o;9132:581::-;9276:13;;9194:7;;9268:22;;239:4;9314:26;;9310:397;;;-1:-1:-1;9363:1:4;;9132:581;-1:-1:-1;;9132:581:4:o;9310:397::-;284:4;9385:25;;;:83;;-1:-1:-1;328:4:4;9415:25;;;;;:52;;-1:-1:-1;371:4:4;9444:23;;9415:52;9381:326;;;-1:-1:-1;9491:1:4;;9132:581;-1:-1:-1;;9132:581:4:o;9381:326::-;328:4;9513:24;;9509:198;;;9599:21;9619:1;284:4;9599:21;:::i;:::-;9590:31;;;;:5;:31;:::i;:::-;:35;;9624:1;9590:35;:::i;9509:198::-;9672:19;9690:1;371:4;9672:19;:::i;7817:1263::-;7983:13;;7876:7;;;;7975:22;;239:4;8021:26;;8017:1032;;;8073:1;8063:11;;8017:1032;;;284:4;8095:25;;8091:958;;;8146:26;239:4;8146:5;:26;:::i;:::-;:30;;8175:1;8146:30;:::i;:::-;8136:40;;8091:958;;;328:4;8197:24;;8193:856;;;8290:4;8283:5;8279:16;8369:1;8361:6;8357:14;8347:24;;8508:7;8504:2;8500:16;8495:3;8491:26;8482:6;8476:13;8472:46;8605:1;8596:7;8592:15;8583:7;8579:29;8568:40;;;;8193:856;;;371:4;8642:23;;8638:411;;;8691:24;328:4;8691:5;:24;:::i;8638:411::-;8803:4;8796:5;8792:16;8847:1;8839:6;8835:14;8825:24;;8918:7;8914:2;8910:16;8905:3;8901:26;8892:6;8886:13;8882:46;9022:1;9013:7;9009:15;9000:7;8996:29;8985:40;;;;8638:411;-1:-1:-1;9066:7:4;7817:1263;-1:-1:-1;;7817:1263:4:o;2390:281::-;2459:7;2468;2487:14;2504:27;2519:4;:11;;;2504:14;:27::i;:::-;2487:44;;2541:14;2572:6;2558:4;:11;;;:20;;;;:::i;:::-;2541:37;;2588:11;2613:6;2602:4;:8;;;:17;;;;:::i;:::-;2652:6;;2588:31;;-1:-1:-1;2390:281:4;;-1:-1:-1;;;;2390:281:4:o;9871:768::-;9952:3;9959:1;9952:8;9948:21;;9871:768;;;:::o;9948:21::-;408:2;10033:16;;10026:194;;10123:10;;10110:24;;10162:16;408:2;10129:3;10162:16;:::i;:::-;;-1:-1:-1;10192:17:4;408:2;10192:17;;:::i;:::-;;-1:-1:-1;10051:16:4;408:2;10051:16;;:::i;:::-;;;10026:194;;;10234:7;;10230:403;;10341:12;10381:1;10362:15;10374:3;408:2;10362:15;:::i;:::-;10356:22;;:3;:22;:::i;:::-;:26;;;;:::i;:::-;10442:10;;10517:11;;10513:22;;10454:9;;10438:26;10587:21;10574:35;;-1:-1:-1;10230:403:4;9871:768;;;:::o;245:196:11:-;313:20;;373:42;362:54;;352:65;;342:93;;431:1;428;421:12;446:260;514:6;522;575:2;563:9;554:7;550:23;546:32;543:52;;;591:1;588;581:12;543:52;614:29;633:9;614:29;:::i;:::-;604:39;;662:38;696:2;685:9;681:18;662:38;:::i;:::-;652:48;;446:260;;;;;:::o;711:186::-;770:6;823:2;811:9;802:7;798:23;794:32;791:52;;;839:1;836;829:12;791:52;862:29;881:9;862:29;:::i;1084:1141::-;1239:6;1247;1255;1263;1316:2;1304:9;1295:7;1291:23;1287:32;1284:52;;;1332:1;1329;1322:12;1284:52;1372:9;1359:23;1401:18;1442:2;1434:6;1431:14;1428:34;;;1458:1;1455;1448:12;1428:34;1496:6;1485:9;1481:22;1471:32;;1541:7;1534:4;1530:2;1526:13;1522:27;1512:55;;1563:1;1560;1553:12;1512:55;1603:2;1590:16;1629:2;1621:6;1618:14;1615:34;;;1645:1;1642;1635:12;1615:34;1700:7;1693:4;1683:6;1680:1;1676:14;1672:2;1668:23;1664:34;1661:47;1658:67;;;1721:1;1718;1711:12;1658:67;1752:4;1744:13;;;;-1:-1:-1;1776:6:11;-1:-1:-1;1820:20:11;;;1807:34;;1853:16;;;1850:36;;;1882:1;1879;1872:12;1850:36;1920:8;1909:9;1905:24;1895:34;;1967:7;1960:4;1956:2;1952:13;1948:27;1938:55;;1989:1;1986;1979:12;1938:55;2031:2;2018:16;2059:2;2049:8;2046:16;2043:36;;;2075:1;2072;2065:12;2043:36;2135:7;2128:4;2120;2110:8;2106:19;2102:2;2098:28;2094:39;2091:52;2088:72;;;2156:1;2153;2146:12;2088:72;1084:1141;;;;-1:-1:-1;;2187:4:11;2179:13;;-1:-1:-1;;;1084:1141:11:o;2744:184::-;2796:77;2793:1;2786:88;2893:4;2890:1;2883:15;2917:4;2914:1;2907:15;2933:334;3004:2;2998:9;3060:2;3050:13;;3065:66;3046:86;3034:99;;3163:18;3148:34;;3184:22;;;3145:62;3142:88;;;3210:18;;:::i;:::-;3246:2;3239:22;2933:334;;-1:-1:-1;2933:334:11:o;3272:1631::-;3324:5;3354:4;3398:3;3393:2;3385:6;3381:15;3377:25;3367:53;;3416:1;3413;3406:12;3367:53;3452:6;3439:20;3478:4;3501:18;3538:2;3534;3531:10;3528:36;;;3544:18;;:::i;:::-;3590:2;3587:1;3583:10;3613:28;3637:2;3633;3629:11;3613:28;:::i;:::-;3675:15;;;3745;;;3741:24;;;3706:12;;;;3777:15;;;3774:35;;;3805:1;3802;3795:12;3774:35;3841:2;3833:6;3829:15;3818:26;;3853:1021;3869:6;3864:3;3861:15;3853:1021;;;3955:3;3942:17;3991:2;3978:11;3975:19;3972:109;;;4035:1;4064:2;4060;4053:14;3972:109;4104:24;;4163:2;4155:11;;4151:21;-1:-1:-1;4141:119:11;;4214:1;4243:2;4239;4232:14;4141:119;4304:2;4300;4296:11;4283:25;4332:2;4357;4353;4350:10;4347:36;;;4363:18;;:::i;:::-;4411:110;4517:2;4448:66;4443:2;4439;4435:11;4431:84;4427:93;4411:110;:::i;:::-;4550:2;4541:7;4534:19;4595:3;4589;4584:2;4580;4576:11;4572:21;4569:30;4566:123;;;4641:1;4671:3;4666;4659:16;4566:123;4747:2;4741:3;4737:2;4733:12;4728:2;4719:7;4715:16;4702:48;4797:1;4774:16;;;4770:25;;4763:36;;;;-1:-1:-1;4812:20:11;;-1:-1:-1;3886:12:11;;;;4852;;;;3853:1021;;;4892:5;3272:1631;-1:-1:-1;;;;;;;;;3272:1631:11:o;4908:986::-;5105:6;5113;5121;5129;5137;5190:3;5178:9;5169:7;5165:23;5161:33;5158:53;;;5207:1;5204;5197:12;5158:53;5230:29;5249:9;5230:29;:::i;:::-;5220:39;;5306:2;5295:9;5291:18;5278:32;5268:42;;5361:2;5350:9;5346:18;5333:32;5384:18;5425:2;5417:6;5414:14;5411:34;;;5441:1;5438;5431:12;5411:34;5464:59;5515:7;5506:6;5495:9;5491:22;5464:59;:::i;:::-;5454:69;;5576:2;5565:9;5561:18;5548:32;5532:48;;5605:2;5595:8;5592:16;5589:36;;;5621:1;5618;5611:12;5589:36;5644:61;5697:7;5686:8;5675:9;5671:24;5644:61;:::i;:::-;5634:71;;5758:3;5747:9;5743:19;5730:33;5714:49;;5788:2;5778:8;5775:16;5772:36;;;5804:1;5801;5794:12;5772:36;;5827:61;5880:7;5869:8;5858:9;5854:24;5827:61;:::i;:::-;5817:71;;;4908:986;;;;;;;;:::o;6113:184::-;6165:77;6162:1;6155:88;6262:4;6259:1;6252:15;6286:4;6283:1;6276:15;6302:128;6369:9;;;6390:11;;;6387:37;;;6404:18;;:::i;6435:168::-;6508:9;;;6539;;6556:15;;;6550:22;;6536:37;6526:71;;6577:18;;:::i;6608:184::-;6660:77;6657:1;6650:88;6757:4;6754:1;6747:15;6781:4;6778:1;6771:15;6797:120;6837:1;6863;6853:35;;6868:18;;:::i;:::-;-1:-1:-1;6902:9:11;;6797:120::o;6922:125::-;6987:9;;;7008:10;;;7005:36;;;7021:18;;:::i;7052:184::-;7104:77;7101:1;7094:88;7201:4;7198:1;7191:15;7225:4;7222:1;7215:15;7241:171;7308:20;;7368:18;7357:30;;7347:41;;7337:69;;7402:1;7399;7392:12;7417:707;7507:6;7560:2;7548:9;7539:7;7535:23;7531:32;7528:52;;;7576:1;7573;7566:12;7528:52;7609:2;7603:9;7651:2;7643:6;7639:15;7720:6;7708:10;7705:22;7684:18;7672:10;7669:34;7666:62;7663:88;;;7731:18;;:::i;:::-;7767:2;7760:22;7804:23;;7867:34;7856:46;;7846:57;;7836:85;;7917:1;7914;7907:12;7836:85;7930:21;;7984:37;8017:2;8002:18;;7984:37;:::i;:::-;7979:2;7971:6;7967:15;7960:62;8055:37;8088:2;8077:9;8073:18;8055:37;:::i;:::-;8050:2;8038:15;;8031:62;8042:6;7417:707;-1:-1:-1;;;7417:707:11:o;8545:602::-;8642:6;8695:2;8683:9;8674:7;8670:23;8666:32;8663:52;;;8711:1;8708;8701:12;8663:52;8744:2;8738:9;8786:2;8778:6;8774:15;8855:6;8843:10;8840:22;8819:18;8807:10;8804:34;8801:62;8798:88;;;8866:18;;:::i;:::-;8902:2;8895:22;8941:16;;8926:32;;9001:2;8986:18;;8980:25;9045:12;9034:24;;9024:35;;9014:63;;9073:1;9070;9063:12;9014:63;9105:2;9093:15;;9086:30;9097:6;8545:602;-1:-1:-1;;;8545:602:11:o;11819:195::-;11858:3;11889:66;11882:5;11879:77;11876:103;;11959:18;;:::i;:::-;-1:-1:-1;12006:1:11;11995:13;;11819:195::o;12288:112::-;12320:1;12346;12336:35;;12351:18;;:::i;:::-;-1:-1:-1;12385:9:11;;12288:112::o;12405:184::-;12457:77;12454:1;12447:88;12554:4;12551:1;12544:15;12578:4;12575:1;12568:15;12594:151;12684:4;12677:12;;;12663;;;12659:31;;12702:14;;12699:40;;;12719:18;;:::i;12750:482::-;12839:1;12882:5;12839:1;12896:330;12917:7;12907:8;12904:21;12896:330;;;13036:4;12968:66;12964:77;12958:4;12955:87;12952:113;;;13045:18;;:::i;:::-;13095:7;13085:8;13081:22;13078:55;;;13115:16;;;;13078:55;13194:22;;;;13154:15;;;;12896:330;;;12900:3;12750:482;;;;;:::o;13237:866::-;13286:5;13316:8;13306:80;;-1:-1:-1;13357:1:11;13371:5;;13306:80;13405:4;13395:76;;-1:-1:-1;13442:1:11;13456:5;;13395:76;13487:4;13505:1;13500:59;;;;13573:1;13568:130;;;;13480:218;;13500:59;13530:1;13521:10;;13544:5;;;13568:130;13605:3;13595:8;13592:17;13589:43;;;13612:18;;:::i;:::-;-1:-1:-1;;13668:1:11;13654:16;;13683:5;;13480:218;;13782:2;13772:8;13769:16;13763:3;13757:4;13754:13;13750:36;13744:2;13734:8;13731:16;13726:2;13720:4;13717:12;13713:35;13710:77;13707:159;;;-1:-1:-1;13819:19:11;;;13851:5;;13707:159;13898:34;13923:8;13917:4;13898:34;:::i;:::-;14028:6;13960:66;13956:79;13947:7;13944:92;13941:118;;;14039:18;;:::i;:::-;14077:20;;13237:866;-1:-1:-1;;;13237:866:11:o;14108:131::-;14168:5;14197:36;14224:8;14218:4;14197:36;:::i

Swarm Source

none://164736f6c6343000814000a

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

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