FRAX Price: $1.02 (+5.24%)

Contract

0x90EB2F13Acf1bc35c2c40c0EBaff2De4d2Eb0d6b

Overview

FRAX Balance | FXTL Balance

0 FRAX | 3,388 FXTL

FRAX Value

$0.00

Token Holdings

More Info

Private Name Tags

Transaction Hash
Block
From
To

There are no matching entries

1 Token Transfer found.

View more zero value Internal Transactions in Advanced View mode

Advanced mode:

Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
VeFXSAggregator

Compiler Version
v0.8.26+commit.8a97fa7a

Optimization Enabled:
Yes with 100000 runs

Other Settings:
default evmVersion, MIT license

Contract Source Code (Solidity)

/**
 *Submitted for verification at fraxscan.com on 2024-06-07
*/

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;


// lib/frax-standard-solidity/lib/forge-std/src/console2.sol

/// @dev The original console.sol uses `int` and `uint` for computing function selectors, but it should
/// use `int256` and `uint256`. This modified version fixes that. This version is recommended
/// over `console.sol` if you don't need compatibility with Hardhat as the logs will show up in
/// forge stack traces. If you do need compatibility with Hardhat, you must use `console.sol`.
/// Reference: https://github.com/NomicFoundation/hardhat/issues/2178
library console2 {
    address constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67);

    function _castLogPayloadViewToPure(
        function(bytes memory) internal view fnIn
    ) internal pure returns (function(bytes memory) internal pure fnOut) {
        assembly {
            fnOut := fnIn
        }
    }

    function _sendLogPayload(bytes memory payload) internal pure {
        _castLogPayloadViewToPure(_sendLogPayloadView)(payload);
    }

    function _sendLogPayloadView(bytes memory payload) private view {
        uint256 payloadLength = payload.length;
        address consoleAddress = CONSOLE_ADDRESS;
        /// @solidity memory-safe-assembly
        assembly {
            let payloadStart := add(payload, 32)
            let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0)
        }
    }

    function log() internal pure {
        _sendLogPayload(abi.encodeWithSignature("log()"));
    }

    function logInt(int256 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(int256)", p0));
    }

    function logUint(uint256 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256)", p0));
    }

    function logString(string memory p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string)", p0));
    }

    function logBool(bool p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
    }

    function logAddress(address p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address)", p0));
    }

    function logBytes(bytes memory p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes)", p0));
    }

    function logBytes1(bytes1 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0));
    }

    function logBytes2(bytes2 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0));
    }

    function logBytes3(bytes3 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0));
    }

    function logBytes4(bytes4 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0));
    }

    function logBytes5(bytes5 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0));
    }

    function logBytes6(bytes6 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0));
    }

    function logBytes7(bytes7 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0));
    }

    function logBytes8(bytes8 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0));
    }

    function logBytes9(bytes9 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0));
    }

    function logBytes10(bytes10 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0));
    }

    function logBytes11(bytes11 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0));
    }

    function logBytes12(bytes12 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0));
    }

    function logBytes13(bytes13 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0));
    }

    function logBytes14(bytes14 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0));
    }

    function logBytes15(bytes15 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0));
    }

    function logBytes16(bytes16 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0));
    }

    function logBytes17(bytes17 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0));
    }

    function logBytes18(bytes18 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0));
    }

    function logBytes19(bytes19 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0));
    }

    function logBytes20(bytes20 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0));
    }

    function logBytes21(bytes21 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0));
    }

    function logBytes22(bytes22 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0));
    }

    function logBytes23(bytes23 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0));
    }

    function logBytes24(bytes24 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0));
    }

    function logBytes25(bytes25 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0));
    }

    function logBytes26(bytes26 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0));
    }

    function logBytes27(bytes27 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0));
    }

    function logBytes28(bytes28 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0));
    }

    function logBytes29(bytes29 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0));
    }

    function logBytes30(bytes30 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0));
    }

    function logBytes31(bytes31 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0));
    }

    function logBytes32(bytes32 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0));
    }

    function log(uint256 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256)", p0));
    }

    function log(int256 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(int256)", p0));
    }

    function log(string memory p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string)", p0));
    }

    function log(bool p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
    }

    function log(address p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address)", p0));
    }

    function log(uint256 p0, uint256 p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256)", p0, p1));
    }

    function log(uint256 p0, string memory p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string)", p0, p1));
    }

    function log(uint256 p0, bool p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool)", p0, p1));
    }

    function log(uint256 p0, address p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address)", p0, p1));
    }

    function log(string memory p0, uint256 p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256)", p0, p1));
    }

    function log(string memory p0, int256 p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,int256)", p0, p1));
    }

    function log(string memory p0, string memory p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1));
    }

    function log(string memory p0, bool p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1));
    }

    function log(string memory p0, address p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1));
    }

    function log(bool p0, uint256 p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256)", p0, p1));
    }

    function log(bool p0, string memory p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1));
    }

    function log(bool p0, bool p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1));
    }

    function log(bool p0, address p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1));
    }

    function log(address p0, uint256 p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256)", p0, p1));
    }

    function log(address p0, string memory p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1));
    }

    function log(address p0, bool p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1));
    }

    function log(address p0, address p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1));
    }

    function log(uint256 p0, uint256 p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256)", p0, p1, p2));
    }

    function log(uint256 p0, uint256 p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string)", p0, p1, p2));
    }

    function log(uint256 p0, uint256 p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool)", p0, p1, p2));
    }

    function log(uint256 p0, uint256 p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address)", p0, p1, p2));
    }

    function log(uint256 p0, string memory p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256)", p0, p1, p2));
    }

    function log(uint256 p0, string memory p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string)", p0, p1, p2));
    }

    function log(uint256 p0, string memory p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool)", p0, p1, p2));
    }

    function log(uint256 p0, string memory p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address)", p0, p1, p2));
    }

    function log(uint256 p0, bool p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256)", p0, p1, p2));
    }

    function log(uint256 p0, bool p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string)", p0, p1, p2));
    }

    function log(uint256 p0, bool p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool)", p0, p1, p2));
    }

    function log(uint256 p0, bool p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address)", p0, p1, p2));
    }

    function log(uint256 p0, address p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256)", p0, p1, p2));
    }

    function log(uint256 p0, address p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string)", p0, p1, p2));
    }

    function log(uint256 p0, address p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool)", p0, p1, p2));
    }

    function log(uint256 p0, address p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address)", p0, p1, p2));
    }

    function log(string memory p0, uint256 p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256)", p0, p1, p2));
    }

    function log(string memory p0, uint256 p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string)", p0, p1, p2));
    }

    function log(string memory p0, uint256 p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool)", p0, p1, p2));
    }

    function log(string memory p0, uint256 p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address)", p0, p1, p2));
    }

    function log(string memory p0, string memory p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256)", p0, p1, p2));
    }

    function log(string memory p0, string memory p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2));
    }

    function log(string memory p0, string memory p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2));
    }

    function log(string memory p0, string memory p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2));
    }

    function log(string memory p0, bool p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256)", p0, p1, p2));
    }

    function log(string memory p0, bool p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2));
    }

    function log(string memory p0, bool p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2));
    }

    function log(string memory p0, bool p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2));
    }

    function log(string memory p0, address p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256)", p0, p1, p2));
    }

    function log(string memory p0, address p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2));
    }

    function log(string memory p0, address p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2));
    }

    function log(string memory p0, address p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2));
    }

    function log(bool p0, uint256 p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256)", p0, p1, p2));
    }

    function log(bool p0, uint256 p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string)", p0, p1, p2));
    }

    function log(bool p0, uint256 p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool)", p0, p1, p2));
    }

    function log(bool p0, uint256 p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address)", p0, p1, p2));
    }

    function log(bool p0, string memory p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256)", p0, p1, p2));
    }

    function log(bool p0, string memory p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2));
    }

    function log(bool p0, string memory p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2));
    }

    function log(bool p0, string memory p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2));
    }

    function log(bool p0, bool p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256)", p0, p1, p2));
    }

    function log(bool p0, bool p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2));
    }

    function log(bool p0, bool p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2));
    }

    function log(bool p0, bool p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2));
    }

    function log(bool p0, address p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256)", p0, p1, p2));
    }

    function log(bool p0, address p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2));
    }

    function log(bool p0, address p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2));
    }

    function log(bool p0, address p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2));
    }

    function log(address p0, uint256 p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256)", p0, p1, p2));
    }

    function log(address p0, uint256 p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string)", p0, p1, p2));
    }

    function log(address p0, uint256 p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool)", p0, p1, p2));
    }

    function log(address p0, uint256 p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address)", p0, p1, p2));
    }

    function log(address p0, string memory p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256)", p0, p1, p2));
    }

    function log(address p0, string memory p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2));
    }

    function log(address p0, string memory p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2));
    }

    function log(address p0, string memory p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2));
    }

    function log(address p0, bool p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256)", p0, p1, p2));
    }

    function log(address p0, bool p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2));
    }

    function log(address p0, bool p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2));
    }

    function log(address p0, bool p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2));
    }

    function log(address p0, address p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256)", p0, p1, p2));
    }

    function log(address p0, address p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2));
    }

    function log(address p0, address p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2));
    }

    function log(address p0, address p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2));
    }

    function log(uint256 p0, uint256 p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,string)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,address)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,string)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,address)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,string)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,address)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,string)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,address)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,string)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,address)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,string)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,address)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,string)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,address)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,string)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,bool)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,address)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,string)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,bool)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,address)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,string)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,bool)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,address)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,string)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,bool)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,address)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,string)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,bool)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,address)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,string)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,bool)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,address)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,string)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,bool)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,address)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3));
    }

}

// node_modules/@openzeppelin/contracts/security/ReentrancyGuard.sol

// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;

        _;

        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }
}

// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol

// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) external returns (bool);
}

// node_modules/@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol

// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

// node_modules/@openzeppelin/contracts/utils/Address.sol

// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)

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

        return account.code.length > 0;
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// node_modules/@openzeppelin/contracts/utils/Context.sol

// OpenZeppelin Contracts v4.4.1 (utils/Context.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 Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

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

// src/contracts/VestedFXS-and-Flox/FPISLocker/IlFPISStructs.sol

// @version 0.2.8

/**
 * ====================================================================
 * |     ______                   _______                             |
 * |    / _____________ __  __   / ____(_____  ____ _____  ________   |
 * |   / /_  / ___/ __ `| |/_/  / /_  / / __ \/ __ `/ __ \/ ___/ _ \  |
 * |  / __/ / /  / /_/ _>  <   / __/ / / / / / /_/ / / / / /__/  __/  |
 * | /_/   /_/   \__,_/_/|_|  /_/   /_/_/ /_/\__,_/_/ /_/\___/\___/   |
 * |                                                                  |
 * ====================================================================
 * ======================== lFPISStructs ==============================
 * ====================================================================
 * Structs of lFPIS contracts (lFPIS)
 * Frax Finance: https://github.com/FraxFinance
 */
interface IlFPISStructs {
    /// @notice Detailed lock info for a user
    /// @param user Address of the user
    /// @param allLocks All of the locks of the user
    /// @param numberOfLocks The total number of locks that the user has
    /// @param activeLocks Only the active locks of the user
    /// @param expiredLocks Only the expired locks of the user
    /// @param totalFpis The total amount of FPIS that the user has for all, active, and expired locks respectively
    struct DetailedUserLockInfo {
        address user;
        uint256 numberOfLocks;
        LockedBalanceExtended[] allLocks;
        LockedBalanceExtended[] activeLocks;
        LockedBalanceExtended[] expiredLocks;
        int128[3] totalFpis;
    }

    /// @notice Basic information about a lock
    /// @param amount The amount that is locked
    /// @param end The ending timestamp for the lock
    /// @dev We cannot really do block numbers per se b/c slope is per time, not per block and per block could be fairly bad b/c Ethereum changes blocktimes. What we can do is to extrapolate ***At functions
    struct LockedBalance {
        int128 amount;
        uint128 end; // This should more than suffice for our needs and allows the struct to be packed
    }

    /// @notice Extended information about a lock
    /// @param id The ID of the lock
    /// @param index The index of the lock. If index is 0, do not trust it unless isInUse is also true
    /// @param amount The amount that is locked
    /// @param end The ending timestamp for the lock
    struct LockedBalanceExtended {
        uint256 id;
        uint128 index;
        int128 amount;
        uint128 end;
    }

    /// @notice Lock ID Info. Cannot be a simple mapping because lock indeces are in constant flux and index 0 vs null is ambiguous.
    /// @param id The ID of the lock
    /// @param index The index of the lock. If index is 0, do not trust it unless isInUse is also true
    /// @param isInUse If the lock ID is currently in use
    struct LockIdIdxInfo {
        uint256 id;
        uint128 index;
        bool isInUse;
    }

    /// @notice Point in a user's lock
    /// @param bias The bias of the point
    /// @param slope The slope of the point
    /// @param ts The timestamp of the point
    /// @param blk The block of the point
    /// @param fpisAmt The amount of FPIS at the point
    struct Point {
        int128 bias;
        int128 slope; // - dweight / dt
        uint256 ts;
        uint256 blk; // block
        uint256 fpisAmt;
    }

    /// @notice Longest lock info for a user
    /// @param lock The longest lock of the user
    /// @param lockIndex The index of the longest lock
    /// @param user The address of the user
    struct LongestLock {
        LockedBalance lock;
        uint128 lockIndex;
        address user;
    }
}

// src/contracts/VestedFXS-and-Flox/Flox/TransferHelper.sol

// helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false
library TransferHelper {
    error TransferHelperApproveFailed();
    error TransferHelperTransferFailed();
    error TransferHelperTransferFromFailed();
    error TransferHelperTransferETHFailed();

    function safeApprove(address token, address to, uint256 value) internal {
        // bytes4(keccak256(bytes('approve(address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
        // require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: APPROVE_FAILED');
        if (!success || (data.length != 0 && !abi.decode(data, (bool)))) revert TransferHelperApproveFailed();
    }

    function safeTransfer(address token, address to, uint256 value) internal {
        // bytes4(keccak256(bytes('transfer(address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
        // require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FAILED');
        if (!success || (data.length != 0 && !abi.decode(data, (bool)))) revert TransferHelperTransferFailed();
    }

    function safeTransferFrom(address token, address from, address to, uint256 value) internal {
        // bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
        // require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FROM_FAILED');
        if (!success || (data.length != 0 && !abi.decode(data, (bool)))) revert TransferHelperTransferFromFailed();
    }

    function safeTransferETH(address to, uint256 value) internal {
        (bool success, ) = to.call{ value: value }(new bytes(0));
        // require(success, 'TransferHelper: ETH_TRANSFER_FAILED');
        if (!success) revert TransferHelperTransferETHFailed();
    }
}

// src/contracts/VestedFXS-and-Flox/VestedFXS/IveFXSStructs.sol

// @version 0.2.8

/**
 * ====================================================================
 * |     ______                   _______                             |
 * |    / _____________ __  __   / ____(_____  ____ _____  ________   |
 * |   / /_  / ___/ __ `| |/_/  / /_  / / __ \/ __ `/ __ \/ ___/ _ \  |
 * |  / __/ / /  / /_/ _>  <   / __/ / / / / / /_/ / / / / /__/  __/  |
 * | /_/   /_/   \__,_/_/|_|  /_/   /_/_/ /_/\__,_/_/ /_/\___/\___/   |
 * |                                                                  |
 * ====================================================================
 * =============================== veFXS ==============================
 * ====================================================================
 * Structs VestedFXS (veFXS)
 * Frax Finance: https://github.com/FraxFinance
 */
interface IveFXSStructs {
    /// @notice Detailed lock info for a user
    /// @param user Address of the user
    /// @param allLocks All of the locks of the user
    /// @param numberOfLocks The total number of locks that the user has
    /// @param activeLocks Only the active locks of the user
    /// @param expiredLocks Only the expired locks of the user
    /// @param totalFxs The total amount of FXS that the user has for all, active, and expired locks respectively
    struct DetailedUserLockInfo {
        address user;
        uint256 numberOfLocks;
        LockedBalanceExtended[] allLocks;
        LockedBalanceExtended[] activeLocks;
        LockedBalanceExtended[] expiredLocks;
        int128[3] totalFxs;
    }

    /// @notice Basic information about a lock
    /// @param amount The amount that is locked
    /// @param end The ending timestamp for the lock
    /// @dev We cannot really do block numbers per se b/c slope is per time, not per block and per block could be fairly bad b/c Ethereum changes blocktimes. What we can do is to extrapolate ***At functions
    struct LockedBalance {
        int128 amount;
        uint128 end; // This should more than suffice for our needs and allows the struct to be packed
    }

    /// @notice Extended information about a lock
    /// @param id The ID of the lock
    /// @param index The index of the lock. If index is 0, do not trust it unless isInUse is also true
    /// @param amount The amount that is locked
    /// @param end The ending timestamp for the lock
    struct LockedBalanceExtended {
        uint256 id;
        uint128 index;
        int128 amount;
        uint128 end;
    }

    /// @notice Extended information about a lock
    /// @param id The ID of the lock
    /// @param index The index of the lock. If index is 0, do not trust it unless isInUse is also true
    /// @param amount The amount that is locked
    /// @param end The ending timestamp for the lock
    /// @param location The address where the lock is being held
    /// @param estimatedCurrLockVeFXS Estimated veFXS of this lock based on amount, end, and when this struct was generated
    struct LockedBalanceExtendedV2 {
        uint256 id;
        uint128 index;
        int128 amount;
        uint128 end;
        address location;
        uint256 estimatedCurrLockVeFXS;
    }

    /// @notice Lock ID Info. Cannot be a simple mapping because lock indeces are in constant flux and index 0 vs null is ambiguous.
    /// @param id The ID of the lock
    /// @param index The index of the lock. If index is 0, do not trust it unless isInUse is also true
    /// @param isInUse If the lock ID is currently in use
    struct LockIdIdxInfo {
        uint256 id;
        uint128 index;
        bool isInUse;
    }

    /// @notice Point in a user's lock
    /// @param bias The bias of the point
    /// @param slope The slope of the point
    /// @param ts The timestamp of the point
    /// @param blk The block of the point
    /// @param fxsAmt The amount of FXS at the point
    struct Point {
        int128 bias;
        int128 slope; // - dweight / dt
        uint256 ts;
        uint256 blk; // block
        uint256 fxsAmt;
    }

    /// @notice Longest lock info for a user
    /// @param lock The longest lock of the user
    /// @param lockIndex The index of the longest lock
    /// @param user The address of the user
    struct LongestLock {
        LockedBalance lock;
        uint128 lockIndex;
        address user;
    }
}

// src/contracts/VestedFXS-and-Flox/VestedFXS/OwnedV2.sol

// https://docs.synthetix.io/contracts/Owned
contract OwnedV2 {
    error OwnerCannotBeZero();
    error InvalidOwnershipAcceptance();
    error OnlyOwner();

    address public owner;
    address public nominatedOwner;

    constructor(address _owner) {
        // require(_owner != address(0), "Owner address cannot be 0");
        if (_owner == address(0)) revert OwnerCannotBeZero();
        owner = _owner;
        emit OwnerChanged(address(0), _owner);
    }

    function nominateNewOwner(address _owner) external onlyOwner {
        nominatedOwner = _owner;
        emit OwnerNominated(_owner);
    }

    function acceptOwnership() external {
        // require(msg.sender == nominatedOwner, "You must be nominated before you can accept ownership");
        if (msg.sender != nominatedOwner) revert InvalidOwnershipAcceptance();
        emit OwnerChanged(owner, nominatedOwner);
        owner = nominatedOwner;
        nominatedOwner = address(0);
    }

    modifier onlyOwner() {
        // require(msg.sender == owner, "Only the contract owner may perform this action");
        if (msg.sender != owner) revert OnlyOwner();
        _;
    }

    function _onlyOwner() internal view {
        if (msg.sender != owner) revert OnlyOwner();
    }

    event OwnerNominated(address newOwner);
    event OwnerChanged(address oldOwner, address newOwner);
}

// src/contracts/VestedFXS-and-Flox/VestedFXS/OwnedV2AutoMsgSender.sol

// https://docs.synthetix.io/contracts/Owned
contract OwnedV2AutoMsgSender {
    error OwnerCannotBeZero();
    error InvalidOwnershipAcceptance();
    error OnlyOwner();

    address public owner;
    address public nominatedOwner;

    constructor() {
        owner = msg.sender;
        emit OwnerChanged(address(0), msg.sender);
    }

    function nominateNewOwner(address _owner) external onlyOwner {
        nominatedOwner = _owner;
        emit OwnerNominated(_owner);
    }

    function acceptOwnership() external {
        // require(msg.sender == nominatedOwner, "You must be nominated before you can accept ownership");
        if (msg.sender != nominatedOwner) revert InvalidOwnershipAcceptance();
        emit OwnerChanged(owner, nominatedOwner);
        owner = nominatedOwner;
        nominatedOwner = address(0);
    }

    modifier onlyOwner() {
        // require(msg.sender == owner, "Only the contract owner may perform this action");
        if (msg.sender != owner) revert OnlyOwner();
        _;
    }

    function _onlyOwner() internal view {
        if (msg.sender != owner) revert OnlyOwner();
    }

    event OwnerNominated(address newOwner);
    event OwnerChanged(address oldOwner, address newOwner);
}

// src/contracts/VestedFXS-and-Flox/interfaces/IL1VeFXS.sol

// @version 0.2.8

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

    function LOCKED_SLOT_INDEX() external view returns (uint256);

    function acceptOwnership() external;

    function adminProofVeFXS(address[] memory _addresses, LockedBalance[] memory _lockedBalances) external;

    function balanceOf(address _address) external view returns (uint256 _balance);

    function initialize(address _stateRootOracle, address _owner) external;

    function locked(address account) external view returns (LockedBalance memory);

    function owner() external view returns (address);

    function pendingOwner() external view returns (address);

    function proofVeFXS(
        address _address,
        uint256 _blockNumber,
        bytes[] memory _accountProof,
        bytes[] memory _storageProof1,
        bytes[] memory _storageProof2
    ) external;

    function renounceOwnership() external;

    function transferOwnership(address newOwner) external;

    function veFXSAddress() external view returns (address);
}

// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol

// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

// src/contracts/VestedFXS-and-Flox/VestedFXS/L1VeFXSTotalSupplyOracle.sol

/**
 * ====================================================================
 * |     ______                   _______                             |
 * |    / _____________ __  __   / ____(_____  ____ _____  ________   |
 * |   / /_  / ___/ __ `| |/_/  / /_  / / __ \/ __ `/ __ \/ ___/ _ \  |
 * |  / __/ / /  / /_/ _>  <   / __/ / / / / / /_/ / / / / /__/  __/  |
 * | /_/   /_/   \__,_/_/|_|  /_/   /_/_/ /_/\__,_/_/ /_/\___/\___/   |
 * |                                                                  |
 * ====================================================================
 * ===================== L1VeFXSTotalSupplyOracle =====================
 * ====================================================================
 * Bot-set Oracle for reporting the Ethereum Mainnet veFXS totalSupply() info.
 * Eventually plan to update L1VeFXS with a proof-based solution
 * Frax Finance: https://github.com/FraxFinance
 */

/* solhint-disable max-line-length, not-rely-on-time */

contract L1VeFXSTotalSupplyOracle is OwnedV2 {
    /// @notice The last veFXS totalSupply data point
    uint256 public totalSupplyStored;

    /// @notice The block on Mainnet when the veFXS totalSupply was read
    uint128 public blkWhenTotalSupplyRead;

    /// @notice The timestamp on Mainnet when the veFXS totalSupply was read
    uint128 public tsWhenTotalSupplyRead;

    /// @notice When the information was last updated by the bot
    uint256 public lastBotUpdate;

    /// @notice Address of the bot that is allowed to update the contract
    address public botAddress;

    /**
     * @notice Initialize contract
     * @param _owner The owner of this contract
     * @param _bot Address of the bot that is allowed to post
     * @param _initTtlSupplyStored Initial/seed value of totalSupplyStored
     * @param _initBlkWhenTotalSupplyRead Initial/seed value of blkWhenTotalSupplyRead
     * @param _initTsWhenTtlSupplyRead Initial/seed value of tsWhenTotalSupplyRead
     */
    constructor(
        address _owner,
        address _bot,
        uint256 _initTtlSupplyStored,
        uint128 _initBlkWhenTotalSupplyRead,
        uint128 _initTsWhenTtlSupplyRead
    ) OwnedV2(_owner) {
        // Set bot address
        botAddress = _bot;

        // Set seed values
        totalSupplyStored = _initTtlSupplyStored;
        blkWhenTotalSupplyRead = _initBlkWhenTotalSupplyRead;
        tsWhenTotalSupplyRead = _initTsWhenTtlSupplyRead;
        if (_initTsWhenTtlSupplyRead > 0) lastBotUpdate = _initTsWhenTtlSupplyRead;
    }

    /* ========== MODIFIERS ========== */

    modifier onlyByOwnBot() {
        require(msg.sender == owner || msg.sender == botAddress, "You are not the owner or the bot");
        _;
    }

    /* ============ VIEWS ============ */

    /// @notice Get the most recent totalSupply from Mainnet veFXS
    /// @param _totalSupply The last reported Mainnet veFXS totalSupply
    function totalSupply() external view returns (uint256 _totalSupply) {
        return totalSupplyStored;
    }

    /// @notice Get the most recent totalSupply from Mainnet veFXS along with the time it was read
    /// @param _totalSupply The last reported Mainnet veFXS totalSupply
    /// @param _blk Block when the totalSupply was read on Mainnet
    /// @param _ts Timestamp when the totalSupply was read on Mainnet
    function totalSupplyExtra() external view returns (uint256 _totalSupply, uint128 _blk, uint128 _ts) {
        return (totalSupplyStored, blkWhenTotalSupplyRead, tsWhenTotalSupplyRead);
    }

    // ==============================================================================
    // BOT FUNCTIONS
    // ==============================================================================

    /// @notice Set the most recent totalSupply from Mainnet veFXS
    /// @param _totalSupply The last reported Mainnet veFXS totalSupply
    /// @param _blk Block when the totalSupply was read on Mainnet
    /// @param _ts Timestamp when the totalSupply was read on Mainnet
    function updateInfo(uint256 _totalSupply, uint128 _blk, uint128 _ts) external onlyByOwnBot {
        totalSupplyStored = _totalSupply;
        blkWhenTotalSupplyRead = _blk;
        tsWhenTotalSupplyRead = _ts;
    }

    // ==============================================================================
    // RESTRICTED FUNCTIONS
    // ==============================================================================

    /// @notice Set the bot address
    /// @param _newBot The address of the timelock
    function setTimelock(address _newBot) external onlyOwner {
        botAddress = _newBot;
    }

    // ==============================================================================
    // EVENTS
    // ==============================================================================

    /// @notice When the veFXS info is updated
    /// @param totalSupply veFXS totalSupply from mainnet
    /// @param blk Block when the totalSupply was read on Mainnet
    /// @param ts Timestamp when the totalSupply was read on Mainnet
    event InfoUpdated(uint256 totalSupply, uint128 blk, uint128 ts);
}

// src/contracts/VestedFXS-and-Flox/interfaces/IFPISLocker.sol

// @version 0.2.8

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

interface IFPISLocker is IlFPISStructs {
    function MAXTIME_INT128() external view returns (int128);

    function MAXTIME_UINT256() external view returns (uint256);

    function MAX_CONTRIBUTOR_LOCKS() external view returns (uint8);

    function MAX_USER_LOCKS() external view returns (uint8);

    function MULTIPLIER_UINT256() external view returns (uint256);

    function VOTE_WEIGHT_MULTIPLIER_INT128() external view returns (int128);

    function VOTE_WEIGHT_MULTIPLIER_UINT256() external view returns (uint256);

    function VOTE_END_POWER_BASIS_POINTS_INT128() external view returns (int128);

    function VOTE_END_POWER_BASIS_POINTS_UINT256() external view returns (uint256);

    function MAX_BASIS_POINTS_INT128() external view returns (int128);

    function MAX_BASIS_POINTS_UINT256() external view returns (uint256);

    function FXS_CONVERSION_START_TIMESTAMP() external view returns (uint256);

    function WEEK_UINT128() external view returns (uint128);

    function WEEK_UINT256() external view returns (uint256);

    function acceptTransferOwnership() external;

    function admin() external view returns (address);

    function balanceOf(address _addr) external view returns (uint256 _balance);

    function balanceOfAllLocksAtBlock(address _addr, uint256 _block) external view returns (uint256 _balance);

    function balanceOfAllLocksAtTime(address _addr, uint256 _timestamp) external view returns (uint256 _balance);

    function balanceOfAt(address _addr, uint256 _block) external view returns (uint256 _balance);

    function balanceOfOneLockAtBlock(
        address _addr,
        uint128 _lockIndex,
        uint256 _block
    ) external view returns (uint256 _balance);

    function balanceOfOneLockAtTime(
        address _addr,
        uint128 _lockIndex,
        uint256 _timestamp
    ) external view returns (uint256 _balance);

    function checkpoint() external;

    function commitTransferOwnership(address _addr) external;

    function createLock(address _addr, uint256 _value, uint128 _unlockTime) external returns (uint128);

    function decimals() external view returns (uint256);

    function depositFor(address _addr, uint256 _value, uint128 _lockIndex) external;

    function emergencyUnlockActive() external view returns (bool);

    function epoch() external view returns (uint256);

    function findBlockEpoch(uint256 _block, uint256 _maxEpoch) external view returns (uint256);

    function floxContributors(address) external view returns (bool);

    function futureAdmin() external view returns (address);

    function getLastUserSlope(address _addr, uint128 _lockIndex) external view returns (int128);

    function increaseAmount(uint256 _value, uint128 _lockIndex) external;

    function increaseUnlockTime(uint128 _unlockTime, uint128 _lockIndex) external;

    function indicesToIds(address, uint128) external view returns (uint256);

    function isPaused() external view returns (bool);

    function locked(address, uint256) external view returns (int128 amount, uint128 end);

    function lockedById(address _addr, uint256 _id) external view returns (LockedBalance memory _lockInfo);

    function lockedByIndex(address _addr, uint128 _index) external view returns (LockedBalance memory _lockInfo);

    function lockedEnd(address _addr, uint128 _index) external view returns (uint256);

    function name() external view returns (string memory);

    function nextId(address) external view returns (uint256);

    function numLocks(address) external view returns (uint128);

    function pointHistory(
        uint256
    ) external view returns (int128 bias, int128 slope, uint256 ts, uint256 blk, uint256 fpisAmt);

    function recoverIERC20(address _tokenAddr, uint256 _amount) external;

    function setFloxContributor(address _floxContributor, bool _isFloxContributor) external;

    function setLVPIDUtils(address _lFpisUtilsAddr) external;

    function slopeChanges(uint256) external view returns (int128);

    function supply() external view returns (uint256);

    function supplyAt(Point memory _point, uint256 _t) external view returns (uint256);

    function symbol() external view returns (string memory);

    function toggleContractPause() external;

    function activateEmergencyUnlock() external;

    function fpis() external view returns (address);

    function totalFPISSupply() external view returns (uint256);

    function totalFPISSupplyAt(uint256 _block) external view returns (uint256);

    function totalSupply() external view returns (uint256);

    function totalSupply(uint256 _timestamp) external view returns (uint256);

    function totalSupplyAt(uint256 _block) external view returns (uint256);

    function userPointEpoch(address, uint256) external view returns (uint256);

    function userPointHistory(
        address,
        uint256,
        uint256
    ) external view returns (int128 bias, int128 slope, uint256 ts, uint256 blk, uint256 fpisAmt);

    function userPointHistoryTs(address _addr, uint128 _lockIndex, uint256 _idx) external view returns (uint256);

    function lFpisUtils() external view returns (address);

    function version() external view returns (string memory);

    function withdraw(uint128 _lockIndex) external;
}

// src/contracts/VestedFXS-and-Flox/interfaces/IVestedFXS.sol

// @version 0.2.8

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

interface IVestedFXS is IveFXSStructs {
    function MAXTIME_INT128() external view returns (int128);

    function MAXTIME_UINT256() external view returns (uint256);

    function MAX_CONTRIBUTOR_LOCKS() external view returns (uint8);

    function MAX_USER_LOCKS() external view returns (uint8);

    function MULTIPLIER_UINT256() external view returns (uint256);

    function VOTE_WEIGHT_MULTIPLIER_INT128() external view returns (int128);

    function VOTE_WEIGHT_MULTIPLIER_UINT256() external view returns (uint256);

    function WEEK_UINT128() external view returns (uint128);

    function WEEK_UINT256() external view returns (uint256);

    function acceptTransferOwnership() external;

    function admin() external view returns (address);

    function balanceOf(address _addr) external view returns (uint256 _balance);

    function balanceOfAllLocksAtBlock(address _addr, uint256 _block) external view returns (uint256 _balance);

    function balanceOfAllLocksAtTime(address _addr, uint256 _timestamp) external view returns (uint256 _balance);

    function balanceOfAt(address _addr, uint256 _block) external view returns (uint256 _balance);

    function balanceOfOneLockAtBlock(
        address _addr,
        uint128 _lockIndex,
        uint256 _block
    ) external view returns (uint256 _balance);

    function balanceOfOneLockAtTime(
        address _addr,
        uint128 _lockIndex,
        uint256 _timestamp
    ) external view returns (uint256 _balance);

    function checkpoint() external;

    function commitTransferOwnership(address _addr) external;

    function createLock(address _addr, uint256 _value, uint128 _unlockTime) external returns (uint128, uint256);

    function decimals() external view returns (uint256);

    function depositFor(address _addr, uint256 _value, uint128 _lockIndex) external;

    function emergencyUnlockActive() external view returns (bool);

    function epoch() external view returns (uint256);

    function findBlockEpoch(uint256 _block, uint256 _maxEpoch) external view returns (uint256);

    function floxContributors(address) external view returns (bool);

    function futureAdmin() external view returns (address);

    function getLastUserSlope(address _addr, uint128 _lockIndex) external view returns (int128);

    function increaseAmount(uint256 _value, uint128 _lockIndex) external;

    function increaseUnlockTime(uint128 _unlockTime, uint128 _lockIndex) external;

    function indicesToIds(address, uint128) external view returns (uint256);

    function isPaused() external view returns (bool);

    function locked(address, uint256) external view returns (int128 amount, uint128 end);

    function lockedById(address _addr, uint256 _id) external view returns (LockedBalance memory _lockInfo);

    function lockedByIndex(address _addr, uint128 _index) external view returns (LockedBalance memory _lockInfo);

    function lockedEnd(address _addr, uint128 _index) external view returns (uint256);

    function name() external view returns (string memory);

    function nextId(address) external view returns (uint256);

    function numLocks(address) external view returns (uint128);

    function pointHistory(
        uint256
    ) external view returns (int128 bias, int128 slope, uint256 ts, uint256 blk, uint256 fxsAmt);

    function recoverIERC20(address _tokenAddr, uint256 _amount) external;

    function setFloxContributor(address _floxContributor, bool _isFloxContributor) external;

    function setVeFXSUtils(address _veFxsUtilsAddr) external;

    function slopeChanges(uint256) external view returns (int128);

    function supply() external view returns (uint256);

    function supplyAt(Point memory _point, uint256 _t) external view returns (uint256);

    function symbol() external view returns (string memory);

    function toggleContractPause() external;

    function activateEmergencyUnlock() external;

    function token() external view returns (address);

    function totalFXSSupply() external view returns (uint256);

    function totalFXSSupplyAt(uint256 _block) external view returns (uint256);

    function totalSupply() external view returns (uint256);

    function totalSupply(uint256 _timestamp) external view returns (uint256);

    function totalSupplyAt(uint256 _block) external view returns (uint256);

    function userPointEpoch(address, uint256) external view returns (uint256);

    function userPointHistory(
        address,
        uint256,
        uint256
    ) external view returns (int128 bias, int128 slope, uint256 ts, uint256 blk, uint256 fxsAmt);

    function userPointHistoryTs(address _addr, uint128 _lockIndex, uint256 _idx) external view returns (uint256);

    function veFxsUtils() external view returns (address);

    function version() external view returns (string memory);

    function withdraw(uint128 _lockIndex) external;

    function numberOfFloxContributorCreatedLocks(address _user) external view returns (uint256);
}

// src/contracts/VestedFXS-and-Flox/interfaces/IVestedFXSUtils.sol

// @version 0.2.8

/**
 * ====================================================================
 * |     ______                   _______                             |
 * |    / _____________ __  __   / ____(_____  ____ _____  ________   |
 * |   / /_  / ___/ __ `| |/_/  / /_  / / __ \/ __ `/ __ \/ ___/ _ \  |
 * |  / __/ / /  / /_/ _>  <   / __/ / / / / / /_/ / / / / /__/  __/  |
 * | /_/   /_/   \__,_/_/|_|  /_/   /_/_/ /_/\__,_/_/ /_/\___/\___/   |
 * |                                                                  |
 * ====================================================================
 * ========================= IVestedFXSUtils ==========================
 * ====================================================================
 * Interface for helper and utility functions for VestedFXS
 * Frax Finance: https://github.com/FraxFinance
 */

interface IVestedFXSUtils is IveFXSStructs {
    function getDetailedUserLockInfo(address user) external view returns (DetailedUserLockInfo memory);

    function getDetailedUserLockInfoBulk(address[] memory users) external view returns (DetailedUserLockInfo[] memory);

    function getLongestLock(address user) external view returns (LockedBalance memory, uint128);

    function getLongestLockBulk(address[] memory users) external view returns (LongestLock[] memory);

    function getCrudeExpectedVeFXSOneLock(int128 _fxsAmount, uint128 _lockSecsU128) external view returns (uint256);

    function getCrudeExpectedVeFXSMultiLock(
        int128[] memory _fxsAmounts,
        uint128[] memory _lockSecsU128
    ) external view returns (uint256);

    function getCrudeExpectedVeFXSUser(address _user) external view returns (uint256);
}

// node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol

// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/ERC20.sol)

/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 * For a generic mechanism see {ERC20PresetMinterPauser}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * We have followed general OpenZeppelin Contracts guidelines: functions revert
 * instead returning `false` on failure. This behavior is nonetheless
 * conventional and does not conflict with the expectations of ERC20
 * applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 *
 * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
 * functions have been added to mitigate the well-known issues around setting
 * allowances. See {IERC20-approve}.
 */
contract ERC20 is Context, IERC20, IERC20Metadata {
    mapping(address => uint256) private _balances;

    mapping(address => mapping(address => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * The default value of {decimals} is 18. To select a different value for
     * {decimals} you should overload it.
     *
     * All two of these values are immutable: they can only be set once during
     * construction.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5.05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the value {ERC20} uses, unless this function is
     * overridden;
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view virtual override returns (uint8) {
        return 18;
    }

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view virtual override returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view virtual override returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(address to, uint256 amount) public virtual override returns (bool) {
        address owner = _msgSender();
        _transfer(owner, to, amount);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view virtual override returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
     * `transferFrom`. This is semantically equivalent to an infinite approval.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 amount) public virtual override returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, amount);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20}.
     *
     * NOTE: Does not update the allowance if the current allowance
     * is the maximum `uint256`.
     *
     * Requirements:
     *
     * - `from` and `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     * - the caller must have allowance for ``from``'s tokens of at least
     * `amount`.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual override returns (bool) {
        address spender = _msgSender();
        _spendAllowance(from, spender, amount);
        _transfer(from, to, amount);
        return true;
    }

    /**
     * @dev Atomically increases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, allowance(owner, spender) + addedValue);
        return true;
    }

    /**
     * @dev Atomically decreases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `spender` must have allowance for the caller of at least
     * `subtractedValue`.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
        address owner = _msgSender();
        uint256 currentAllowance = allowance(owner, spender);
        require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
        unchecked {
            _approve(owner, spender, currentAllowance - subtractedValue);
        }

        return true;
    }

    /**
     * @dev Moves `amount` of tokens from `from` to `to`.
     *
     * This internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     */
    function _transfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {
        require(from != address(0), "ERC20: transfer from the zero address");
        require(to != address(0), "ERC20: transfer to the zero address");

        _beforeTokenTransfer(from, to, amount);

        uint256 fromBalance = _balances[from];
        require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
        unchecked {
            _balances[from] = fromBalance - amount;
        }
        _balances[to] += amount;

        emit Transfer(from, to, amount);

        _afterTokenTransfer(from, to, amount);
    }

    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function _mint(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: mint to the zero address");

        _beforeTokenTransfer(address(0), account, amount);

        _totalSupply += amount;
        _balances[account] += amount;
        emit Transfer(address(0), account, amount);

        _afterTokenTransfer(address(0), account, amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, reducing the
     * total supply.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     */
    function _burn(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: burn from the zero address");

        _beforeTokenTransfer(account, address(0), amount);

        uint256 accountBalance = _balances[account];
        require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
        unchecked {
            _balances[account] = accountBalance - amount;
        }
        _totalSupply -= amount;

        emit Transfer(account, address(0), amount);

        _afterTokenTransfer(account, address(0), amount);
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     */
    function _approve(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    /**
     * @dev Updates `owner` s allowance for `spender` based on spent `amount`.
     *
     * Does not update the allowance amount in case of infinite allowance.
     * Revert if not enough allowance is available.
     *
     * Might emit an {Approval} event.
     */
    function _spendAllowance(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
        uint256 currentAllowance = allowance(owner, spender);
        if (currentAllowance != type(uint256).max) {
            require(currentAllowance >= amount, "ERC20: insufficient allowance");
            unchecked {
                _approve(owner, spender, currentAllowance - amount);
            }
        }
    }

    /**
     * @dev Hook that is called before any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * will be transferred to `to`.
     * - when `from` is zero, `amount` tokens will be minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {}

    /**
     * @dev Hook that is called after any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * has been transferred to `to`.
     * - when `from` is zero, `amount` tokens have been minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _afterTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {}
}

// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol

// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    function safeTransfer(
        IERC20 token,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(
        IERC20 token,
        address from,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        uint256 newAllowance = token.allowance(address(this), spender) + value;
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            uint256 newAllowance = oldAllowance - value;
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    }

    function safePermit(
        IERC20Permit token,
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        uint256 nonceBefore = token.nonces(owner);
        token.permit(owner, spender, value, deadline, v, r, s);
        uint256 nonceAfter = token.nonces(owner);
        require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        if (returndata.length > 0) {
            // Return data is optional
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

// src/contracts/VestedFXS-and-Flox/FPISLocker/FPISLockerUtils.sol

// @version 0.2.8

/**
 * ====================================================================
 * |     ______                   _______                             |
 * |    / _____________ __  __   / ____(_____  ____ _____  ________   |
 * |   / /_  / ___/ __ `| |/_/  / /_  / / __ \/ __ `/ __ \/ ___/ _ \  |
 * |  / __/ / /  / /_/ _>  <   / __/ / / / / / /_/ / / / / /__/  __/  |
 * | /_/   /_/   \__,_/_/|_|  /_/   /_/_/ /_/\__,_/_/ /_/\___/\___/   |
 * |                                                                  |
 * ====================================================================
 * ========================= FPISLockerUtils ==========================
 * ====================================================================
 * Helper and utility functions for VestedFXS
 * Frax Finance: https://github.com/FraxFinance
 */

/**
 *
 * Voting escrow to have time-weighted votes
 * Votes have a weight depending on time, so that users are committed
 * to the future of (whatever they are voting for).
 * The weight in this implementation is linear, and lock cannot be more than maxtime:
 * w ^
 * 1 +        /
 *   |      /
 *   |    /
 *   |  /
 *   |/
 * 0 +--------+------> time
 *       maxtime (4 years?)
 */

/**
 * @title FPISLockerUtils
 * @author Frax Finance
 * @notice This utility smart contract provides functions to get extended information from the FPISLocker contract.
 */
contract FPISLockerUtils is IlFPISStructs {
    IFPISLocker public immutable lFPIS;
    IERC20Metadata public immutable fpis;

    uint256 public constant VOTE_END_POWER_BASIS_POINTS_UINT256 = 3330;
    uint256 public constant MAX_BASIS_POINTS_UINT256 = 10_000;

    /**
     * @notice Contract constructor
     * @param _FPISLocker Address of the FPISLocker contract
     */
    constructor(address _FPISLocker) {
        lFPIS = IFPISLocker(_FPISLocker);
        fpis = IERC20Metadata(lFPIS.fpis());
    }

    /**
     * @notice Used to get all of the locks of a given user.
     * @dev The locks are retrieved indiscriminately, regardless of whether they are active or expired.
     * @param _user Address of the user
     * @return _userLockInfo DetailedUserLockInfo for the user. Includes _allLocks, _activeLocks, _expiredLocks, and FXS totals for these respectively
     * @dev This lives on Fraxtal and will mostly be read-called in UIs, so gas not really an issue here
     */
    function getDetailedUserLockInfo(address _user) public view returns (DetailedUserLockInfo memory _userLockInfo) {
        // Get the total number of locks
        uint256 _totalLocks = lFPIS.numLocks(_user);
        uint128 _numberOfActiveLocks;

        // Set the number locks for the user
        _userLockInfo.numberOfLocks = _totalLocks;

        // Set the user
        _userLockInfo.user = _user;

        // Initialize _allLocks
        _userLockInfo.allLocks = new LockedBalanceExtended[](_totalLocks);

        // Initial _isActive, which tracks if a given index is active
        bool[] memory _isActive = new bool[](_totalLocks);

        // Loop through all of the locks
        for (uint256 i; i < _userLockInfo.allLocks.length; ) {
            // Update the _allLocks return data
            LockedBalance memory _thisLock = lFPIS.lockedByIndex(_user, uint128(i));
            _userLockInfo.allLocks[i].id = lFPIS.indicesToIds(_user, uint128(i));
            _userLockInfo.allLocks[i].index = uint128(i);
            _userLockInfo.allLocks[i].amount = _thisLock.amount;
            _userLockInfo.allLocks[i].end = _thisLock.end;
            _userLockInfo.totalFpis[0] += _thisLock.amount;

            // Determine whether it is active or expired
            if (_thisLock.end > block.timestamp) {
                // Update isActive tracking
                _isActive[i] = true;

                // Update _totalFxs for active locks
                _userLockInfo.totalFpis[1] += _thisLock.amount;

                unchecked {
                    ++_numberOfActiveLocks;
                }
            } else {
                // Update _totalFxs for expired locks
                _userLockInfo.totalFpis[2] += _thisLock.amount;
            }
            unchecked {
                ++i;
            }
        }

        // Initialize _activeLocks and _expiredLocks
        _userLockInfo.activeLocks = new LockedBalanceExtended[](_numberOfActiveLocks);
        _userLockInfo.expiredLocks = new LockedBalanceExtended[](_totalLocks - _numberOfActiveLocks);

        // Loop through all of the locks again, this time for assigning to _activeLocks and _expiredLocks
        uint128 _activeCounter;
        uint128 _expiredCounter;
        for (uint256 i; i < _userLockInfo.allLocks.length; ) {
            // Get the lock info
            LockedBalanceExtended memory _thisLock = _userLockInfo.allLocks[i];

            // Sort the lock as either active or expired
            if (_isActive[i]) {
                // Active
                _userLockInfo.activeLocks[_activeCounter] = _thisLock;

                unchecked {
                    ++_activeCounter;
                }
            } else {
                // Expired
                _userLockInfo.expiredLocks[_expiredCounter] = _thisLock;

                unchecked {
                    ++_expiredCounter;
                }
            }

            unchecked {
                ++i;
            }
        }
    }

    /**
     * @notice Used to get all of the locks of the given users. Same underlying code as getDetailedUserLockInfo
     * @dev The locks are retrieved indiscriminately, regardless of whether they are active or expired.
     * @param _users Addresses of the users
     * @return _userLockInfos DetailedUserLockInfo[] for the users. Includes _allLocks, _activeLocks, _expiredLocks, and FXS totals for these respectively
     * @dev This lives on Fraxtal and will mostly be read-called in UIs, so gas not really an issue here
     */
    function getDetailedUserLockInfoBulk(
        address[] memory _users
    ) public view returns (DetailedUserLockInfo[] memory _userLockInfos) {
        // Save the number of user addresses
        uint256 _numUsers = _users.length;

        // Initialize the return array
        _userLockInfos = new DetailedUserLockInfo[](_numUsers);

        // Loop through all of the users and get their detailed lock info
        for (uint256 i = 0; i < _numUsers; ) {
            _userLockInfos[i] = getDetailedUserLockInfo(_users[i]);

            unchecked {
                i++;
            }
        }
    }

    /**
     * @notice Used to get the longest lock of a given user.
     * @dev The longest lock is the lock with the timestamp furthest in the future (can also be in the past if there are no active locks).
     * @param user Address of the user
     * @return The longest lock of the user
     * @return The index of the longest lock
     */
    function getLongestLock(address user) public view returns (LockedBalance memory, uint128) {
        LockedBalance[] memory locks = new LockedBalance[](lFPIS.numLocks(user));
        LockedBalance memory longestLock;
        uint128 longestLockIndex;

        for (uint256 i = 0; i < locks.length; ) {
            uint128 currentEnd = lFPIS.lockedByIndex(user, uint128(i)).end;
            if (currentEnd > longestLock.end) {
                longestLock.end = currentEnd;
                longestLock.amount = lFPIS.lockedByIndex(user, uint128(i)).amount;
                longestLockIndex = uint128(i);
            }

            unchecked {
                i++;
            }
        }

        return (longestLock, longestLockIndex);
    }

    /**
     * @notice Used to get longest locks of muliple users.
     * @dev This returns the longest lock indiscriminately, regardless of whether it is active or expired.
     * @dev The return value is an array of LongestLock structs, which contain the lock, the index of the lock, and the user.
     * @param users Array of addresses of the users
     * @return The LongestLocks of the users
     */
    function getLongestLockBulk(address[] memory users) public view returns (LongestLock[] memory) {
        LongestLock[] memory longestLocks = new LongestLock[](users.length);
        LockedBalance memory longestLock;
        uint128 longestLockIndex;

        for (uint256 i = 0; i < users.length; ) {
            for (uint256 j; j < lFPIS.numLocks(users[i]); ) {
                uint128 currentEnd = lFPIS.lockedByIndex(users[i], uint128(j)).end;
                if (currentEnd > longestLock.end) {
                    longestLock.end = currentEnd;
                    longestLock.amount = lFPIS.lockedByIndex(users[i], uint128(j)).amount;
                    longestLockIndex = uint128(j);
                }

                unchecked {
                    ++j;
                }
            }

            longestLocks[i] = LongestLock({ lock: longestLock, lockIndex: longestLockIndex, user: users[i] });

            delete longestLock;
            delete longestLockIndex;

            unchecked {
                ++i;
            }
        }

        return longestLocks;
    }

    /**
     * @notice Calculate the APPROXIMATE amount of lFPIS, given an FPIS amount and a lock length. Cruder version of balanceOf math. Useful for sanity checks.
     * @param _fpisAmount The amount of FPIS
     * @param _lockSecsU128 The length of the lock
     * @return _expectedLFPIS The expected amount of lFPIS. May be slightly off from actual (~1%)
     * @dev Useful to compare to the slope/bias-based balancedOf to make sure the math is working
     */
    function getCrudeExpectedLFPISOneLock(
        int128 _fpisAmount,
        uint128 _lockSecsU128
    ) public view returns (uint256 _expectedLFPIS) {
        // lFPIS = FPIS in emergency unlock situation
        if (lFPIS.emergencyUnlockActive()) {
            return (uint256(int256(_fpisAmount)) * VOTE_END_POWER_BASIS_POINTS_UINT256) / MAX_BASIS_POINTS_UINT256;
        }

        // Truncate _timeLeft down to the nearest week
        int128 _lockSecsI128 = int128((_lockSecsU128 / lFPIS.WEEK_UINT128()) * lFPIS.WEEK_UINT128());

        // Calculate the expected lFPIS
        _expectedLFPIS = uint256(
            uint128(
                ((_fpisAmount * lFPIS.VOTE_END_POWER_BASIS_POINTS_INT128()) / lFPIS.MAX_BASIS_POINTS_INT128()) +
                    ((_fpisAmount * _lockSecsI128 * lFPIS.VOTE_WEIGHT_MULTIPLIER_INT128()) /
                        lFPIS.MAXTIME_INT128() /
                        lFPIS.MAX_BASIS_POINTS_INT128())
            )
        );
    }

    /**
     * @notice Calculate the APPROXIMATE amount of lFPIS, given FPIS amounts and lock lengths. Cruder version of balanceOf math. Useful for sanity checks.
     * @param _fpisAmounts The amounts of FPIS
     * @param _lockSecsU128 The length of the locks
     * @return _expectedLFPIS The expected amount of lFPIS (summed). May be slightly off from actual (~1%)
     * @dev Useful to compare to the slope/bias-based balancedOf to make sure the math is working
     */
    function getCrudeExpectedLFPISMultiLock(
        int128[] memory _fpisAmounts,
        uint128[] memory _lockSecsU128
    ) public view returns (uint256 _expectedLFPIS) {
        // See if you are in an emergency unlock situation
        bool _isEmergencyUnlockActive = lFPIS.emergencyUnlockActive();

        // Loop through the locks
        for (uint128 i = 0; i < _fpisAmounts.length; ++i) {
            // lFPIS = FPIS in emergency unlock situation
            if (_isEmergencyUnlockActive) {
                _expectedLFPIS +=
                    (uint256(int256(_fpisAmounts[i])) * VOTE_END_POWER_BASIS_POINTS_UINT256) /
                    MAX_BASIS_POINTS_UINT256;
            } else {
                _expectedLFPIS += getCrudeExpectedLFPISOneLock(_fpisAmounts[i], _lockSecsU128[i]);
            }
        }
    }

    /**
     * @notice Calculate the APPROXIMATE amount of lFPIS a specific user should have. Cruder version of balanceOf math. Useful for sanity checks.
     * @param _user The address of the user
     * @return _expectedLFPIS The expected amount of lFPIS (summed). May be slightly off from actual (~1%)
     * @dev Useful to compare to the slope/bias-based balancedOf to make sure the math is working
     */
    function getCrudeExpectedLFPISUser(address _user) public view returns (uint256 _expectedLFPIS) {
        // Get all of the user's locks
        DetailedUserLockInfo memory _userLockInfo = getDetailedUserLockInfo(_user);

        // See if you are in an emergency unlock situation
        bool _isEmergencyUnlockActive = lFPIS.emergencyUnlockActive();

        // Loop through all of the user's locks
        for (uint128 i = 0; i < _userLockInfo.numberOfLocks; ) {
            // Get the lock info
            LockedBalanceExtended memory _lockInfo = _userLockInfo.allLocks[i];

            // For the emergency unlock situation, lFPIS = FPIS
            if (_isEmergencyUnlockActive) {
                _expectedLFPIS +=
                    (uint256(int256(_lockInfo.amount)) * VOTE_END_POWER_BASIS_POINTS_UINT256) /
                    MAX_BASIS_POINTS_UINT256;
            } else {
                // Get the lock time to use
                uint128 _lockSecsToUse;
                if (_lockInfo.end < uint128(block.timestamp)) {
                    _lockSecsToUse = 0;
                } else {
                    _lockSecsToUse = _lockInfo.end - uint128(block.timestamp);
                }

                // Get the approximate lFPIS
                _expectedLFPIS += getCrudeExpectedLFPISOneLock(_lockInfo.amount, _lockSecsToUse);
            }

            unchecked {
                ++i;
            }
        }
    }
}

// src/contracts/VestedFXS-and-Flox/VestedFXS/VeFXSAggregator.sol

// ====================================================================
// |     ______                   _______                             |
// |    / _____________ __  __   / ____(_____  ____ _____  ________   |
// |   / /_  / ___/ __ `| |/_/  / /_  / / __ \/ __ `/ __ \/ ___/ _ \  |
// |  / __/ / /  / /_/ _>  <   / __/ / / / / / /_/ / / / / /__/  __/  |
// | /_/   /_/   \__,_/_/|_|  /_/   /_/_/ /_/\__,_/_/ /_/\___/\___/   |
// |                                                                  |
// ====================================================================
// ========================= VeFXSAggregator ==========================
// ====================================================================
// Looks at various sources of veFXS for a given address. Also gives totalSupply
// Includes:
// 1) L1veFXS: Lives on Fraxtal. Users can prove their Ethereum Mainnet vefxs.vy balance and end time so it is visible on Fraxtal
// 2) VestedFXS: Fraxtal-native veFXS. Basically the same as Mainnet vefxs.vy but lives on Fraxtal
// 3) FPISLocker: Locked FPIS on Fraxtal that eventually will be converted to FXS per https://snapshot.org/#/frax.eth/proposal/0x9ec68015d6f6fd185f600a255e494f4ff926bbdd9b268f4bd712983a6e68fb5a
// 4+) Future capability to add even more sources of veFXS

// Frax Finance: https://github.com/FraxFinance

// Primary Author(s)
// Travis Moore: https://github.com/FortisFortuna

// Reviewer(s) / Contributor(s)
// Jan Turk: https://github.com/ThunderDeliverer
// Dennis: https://github.com/denett
// Sam Kazemian: https://github.com/samkazemian

// Originally inspired by Synthetix.io, but heavily modified by the Frax team (veFXS portion)
// https://github.com/Synthetixio/synthetix/blob/develop/contracts/StakingRewards.sol

contract VeFXSAggregator is OwnedV2AutoMsgSender, ReentrancyGuard, IveFXSStructs {
    using SafeERC20 for ERC20;

    // ==============================================================================
    // STATE VARIABLES
    // ==============================================================================

    // Instances
    // -------------------------
    /// @notice The Fraxtal veFXS contract
    IVestedFXS public veFXS;

    /// @notice The FPIS Locker contract
    IFPISLocker public fpisLocker;

    /// @notice The IL1VeFXS contract (snapshot of Ethereum Mainnet veFXS.vy)
    IL1VeFXS public l1veFXS;

    /// @notice The Fraxtal veFXS veFXSUtils contract
    IVestedFXSUtils public veFXSUtils;

    /// @notice The Fraxtal FPIS Locker FPISLockerUtils contract
    FPISLockerUtils public lFpisUtils;

    /// @notice Oracle on Fraxtal that reports Mainnet veFXS totalSupply.
    L1VeFXSTotalSupplyOracle public l1VeFXSTotalSupplyOracle;

    // Addresses
    // -------------------------
    /// @notice Address of the timelock
    address public timelockAddress;

    /// @notice Array of additional / future veFXS-like contracts
    address[] public addlVeContractsArr;

    /// @notice Whether an address is an additional / future veFXS-like contract
    mapping(address => bool) public addlVeContracts;

    // Misc
    // -------------------------

    /// @notice If the contract was initialized
    bool wasInitialized;

    /// @dev reserve extra storage for future upgrades
    uint256[50] private __gap;

    // ==============================================================================
    // STRUCTS
    // ==============================================================================

    /// @notice A more detailed breakdown of the veFXS supply
    /// @param vestedFXSTotal Fraxtal-native VestedFXS totalSupply
    /// @param fpisLockerTotal FPISLocker's totalSupply
    /// @param l1veFXSTotal Sum of L1veFXS as reported by the L1VeFXSTotalSupplyOracle
    /// @param otherSourcesTotal Sum of the totalSupply's of other veFXS sources
    /// @param grandTotal Grand totalSupply of all veFXS sources
    struct DetailedTotalSupplyInfo {
        uint256 vestedFXSTotal;
        uint256 fpisLockerTotal;
        uint256 l1veFXSTotal;
        uint256 otherSourcesTotal;
        uint256 grandTotal;
    }

    // ==============================================================================
    // MODIFIERS
    // ==============================================================================

    /// @notice A modifier that only allows the contract owner or the timelock to call
    modifier onlyByOwnGov() {
        if (msg.sender != owner && msg.sender != timelockAddress) revert NotOwnerOrTimelock();
        _;
    }

    // ==============================================================================
    // CONSTRUCTOR
    // ==============================================================================

    constructor() {
        // Set the contract as initialized
        wasInitialized = true;
    }

    /**
     * @notice Initialize contract
     * @param _owner The owner of this contract
     * @param _timelockAddress Address of the timelock
     * @param _veAddresses The addresses: 0: veFXS, 1: veFXSUtils, 2: FPIS Locker, 3: FPISLockerUtils, 4: L1VeFXS, 5: L1VeFXSTotalSupplyOracle
     */
    function initialize(address _owner, address _timelockAddress, address[6] memory _veAddresses) public {
        // Safety checks - no validation on admin in case this is initialized without admin
        if (wasInitialized) revert InitializeFailed();

        // Set owner for OwnedV2
        owner = _owner;

        // Set misc addresses
        timelockAddress = _timelockAddress;

        // Set the Fraxtal VestedFXS
        veFXS = IVestedFXS(_veAddresses[0]);
        veFXSUtils = IVestedFXSUtils(_veAddresses[1]);

        // (Optional) Set the FPISLocker
        if ((_veAddresses[2] != address(0)) && (_veAddresses[3] != address(0))) {
            fpisLocker = IFPISLocker(_veAddresses[2]);
            lFpisUtils = FPISLockerUtils(_veAddresses[3]);
        }

        // (Optional) Set the L1VeFXS andL1VeFXSTotalSupplyOracle
        if ((_veAddresses[4] != address(0)) && (_veAddresses[5] != address(0))) {
            l1veFXS = IL1VeFXS(_veAddresses[4]);
            l1VeFXSTotalSupplyOracle = L1VeFXSTotalSupplyOracle(_veAddresses[5]);
        }
    }

    // ==============================================================================
    // VIEWS
    // ==============================================================================

    /// @notice Total veFXS of a user from multiple different sources, such as the FPIS Locker, L1VeFXS, and Fraxtal veFXS
    /// @param _user The user to check
    /// @return _currBal The veFXS balance
    function ttlCombinedVeFXS(address _user) public view returns (uint256 _currBal) {
        // Look at the OG 3 sources first
        // ===========================
        // VestedFXS on Fraxtal
        _currBal = veFXS.balanceOf(_user);

        // (Optional) FPIS Locker on Fraxtal
        if (address(fpisLocker) != address(0)) _currBal += fpisLocker.balanceOf(_user);

        // (Optional) L1VeFXS: snapshot of Ethereum Mainnet veFXS. Lives on Fraxtal
        if ((address(l1veFXS) != address(0)) && (address(l1VeFXSTotalSupplyOracle) != address(0))) {
            _currBal += l1veFXS.balanceOf(_user);
        }

        // (Optional) Look at any extra veFXS sources
        for (uint256 i; i < addlVeContractsArr.length; ) {
            address _veAddr = addlVeContractsArr[i];
            if (_veAddr != address(0)) {
                _currBal += IVestedFXS(_veAddr).balanceOf(_user);
            }

            unchecked {
                ++i;
            }
        }
    }

    /// @notice Detailed veFXS totalSupply from multiple different sources, such as the FPIS Locker, L1VeFXS, and Fraxtal veFXS. Non-checkpointed L1VeFXS is excluded
    /// @return _supplyInfo Detailed breakdown of veFXS from different sources
    function ttlCombinedVeFXSTotalSupplyDetailed() public view returns (DetailedTotalSupplyInfo memory _supplyInfo) {
        // Look at the OG 3 sources first
        // ===========================
        // VestedFXS on Fraxtal
        _supplyInfo.vestedFXSTotal = veFXS.totalSupply();
        _supplyInfo.grandTotal = _supplyInfo.vestedFXSTotal;
        // console2.log("{agg} veFXS.totalSupply(): %s", _supplyInfo.vestedFXSTotal);

        // (Optional) FPIS Locker on Fraxtal
        if (address(fpisLocker) != address(0)) {
            _supplyInfo.fpisLockerTotal = fpisLocker.totalSupply();
            _supplyInfo.grandTotal += _supplyInfo.fpisLockerTotal;
            // console2.log("{agg} fpisLocker.totalSupply(): %s", _supplyInfo.fpisLockerTotal);
        }

        // (Optional) L1VeFXS: snapshot of Ethereum Mainnet veFXS. Lives on Fraxtal
        if ((address(l1veFXS) != address(0)) && (address(l1VeFXSTotalSupplyOracle) != address(0))) {
            _supplyInfo.l1veFXSTotal = l1VeFXSTotalSupplyOracle.totalSupply();
            _supplyInfo.grandTotal += _supplyInfo.l1veFXSTotal;
            // console2.log("{agg} l1VeFXSTotalSupplyOracle.totalSupply(): %s", _supplyInfo.l1veFXSTotal);
        }

        // (Optional) Look at any extra veFXS sources
        for (uint256 i; i < addlVeContractsArr.length; ) {
            address _veAddr = addlVeContractsArr[i];
            if (_veAddr != address(0)) {
                uint256 _thisSupply = IVestedFXS(_veAddr).totalSupply();
                _supplyInfo.otherSourcesTotal += _thisSupply;
                _supplyInfo.grandTotal += _thisSupply;
                // console2.log("{agg} addlVeContractsArr[%s].totalSupply(): %s", i, _thisSupply);
            }

            unchecked {
                ++i;
            }
        }
    }

    /// @notice Total veFXS totalSupply from multiple different sources, such as the FPIS Locker, L1VeFXS, and Fraxtal veFXS. Non-checkpointed L1VeFXS is excluded
    /// @return _totalSupply The veFXS totalSupply from all sources
    /// @dev Summarized version of ttlCombinedVeFXSTotalSupplyDetailed
    function ttlCombinedVeFXSTotalSupply() public view returns (uint256 _totalSupply) {
        DetailedTotalSupplyInfo memory _supplyInfo = ttlCombinedVeFXSTotalSupplyDetailed();
        _totalSupply = _supplyInfo.grandTotal;
    }

    /// @notice Array of all extra veFXS-like contracts
    /// @return _addresses The addresses
    function allAddlVeContractsAddreses() external view returns (address[] memory _addresses) {
        return addlVeContractsArr;
    }

    /// @notice Length of the array of all extra veFXS-like contracts
    /// @return _length The length
    function allAddlVeContractsLength() external view returns (uint256 _length) {
        return addlVeContractsArr.length;
    }

    /// @notice Get all the active locks for a user
    /// @param _account The account to get the locks for
    /// @param _estimateCrudeVeFXS False to save gas. True to add the lock's estimated veFXS
    /// @return _currActiveLocks Array of LockedBalanceExtendedV2 structs (all active locks)
    function getAllCurrActiveLocks(
        address _account,
        bool _estimateCrudeVeFXS
    ) public view returns (LockedBalanceExtendedV2[] memory _currActiveLocks) {
        // Prepare to allocate the return array. Not all of the locks will be active.

        // OG 3 veFXS contracts
        // ===================================
        // Fraxtal VestedFXS
        uint256 _maxArrSize = veFXS.numLocks(_account);

        // (Optional) FPIS Locker
        if (address(fpisLocker) != address(0)) _maxArrSize += fpisLocker.numLocks(_account);

        // (Optional) L1VeFXS
        if ((address(l1veFXS) != address(0)) && (address(l1VeFXSTotalSupplyOracle) != address(0))) {
            _maxArrSize += 1; // Legacy veFXS on Mainnet only has one lock
        }

        // (Optional) Get the total number of locks in the additional veFXS contracts
        for (uint256 i = 0; i < addlVeContractsArr.length; i++) {
            address _veAddr = addlVeContractsArr[i];
            if (_veAddr != address(0)) {
                // Get the total number of locks
                _maxArrSize += IVestedFXS(_veAddr).numLocks(_account);
            }
        }

        // Allocate a temporary dynamic array
        uint256 _activeLockIdx = 0;
        LockedBalanceExtendedV2[] memory _tmpActiveLocks = new LockedBalanceExtendedV2[](_maxArrSize);

        // Go through the OG 3 sources first

        // Fraxtal veFXS
        // -------------------------
        {
            // Get the LockedBalanceExtendeds
            LockedBalanceExtended[] memory _fxtlVeFXSLockedBalExtds = (veFXSUtils.getDetailedUserLockInfo(_account))
                .activeLocks;

            // Loop though the Fraxtal veFXS locks and add them to the combined array
            for (uint256 i; i < _fxtlVeFXSLockedBalExtds.length; ) {
                // Save tmp variable to memory
                IveFXSStructs.LockedBalanceExtended memory _vestedFXSLockInfo = _fxtlVeFXSLockedBalExtds[i];

                // (Optional) Estimate the lock's veFXS based on amount, end, and block.timestamp
                uint256 _estimatedVeFXS;
                if (_estimateCrudeVeFXS) {
                    _estimatedVeFXS = veFXSUtils.getCrudeExpectedVeFXSOneLock(
                        _vestedFXSLockInfo.amount,
                        _vestedFXSLockInfo.end - uint128(block.timestamp)
                    );
                }

                // Add to the temp array
                _tmpActiveLocks[_activeLockIdx] = LockedBalanceExtendedV2({
                    id: _vestedFXSLockInfo.id,
                    index: _vestedFXSLockInfo.index,
                    amount: _vestedFXSLockInfo.amount,
                    end: _vestedFXSLockInfo.end,
                    location: address(veFXS),
                    estimatedCurrLockVeFXS: _estimatedVeFXS
                });

                // Increase the active lock index
                ++_activeLockIdx;

                unchecked {
                    ++i;
                }
            }
        }

        // (Optional) FPIS Locker
        // -------------------------
        if (address(fpisLocker) != address(0)) {
            // Get the LockedBalanceExtendeds
            IlFPISStructs.LockedBalanceExtended[] memory _fpisLockerLockedBalExtds = (
                lFpisUtils.getDetailedUserLockInfo(_account)
            ).activeLocks;

            // Loop though the FPIS Locker locks and add them to the combined array
            for (uint256 i; i < _fpisLockerLockedBalExtds.length; ) {
                // Save tmp variable to memory
                IlFPISStructs.LockedBalanceExtended memory _fpisLockInfo = _fpisLockerLockedBalExtds[i];

                // Double check end time
                if (_fpisLockInfo.end > block.timestamp) {
                    // (Optional) Estimate the lock's veFXS based on amount, end, and block.timestamp
                    uint256 _estimatedVeFXS;
                    if (_estimateCrudeVeFXS) {
                        _estimatedVeFXS = lFpisUtils.getCrudeExpectedLFPISOneLock(
                            _fpisLockInfo.amount,
                            _fpisLockInfo.end - uint128(block.timestamp)
                        );
                    }

                    // Need to save as LockedBalanceExtendedV2
                    _tmpActiveLocks[_activeLockIdx] = LockedBalanceExtendedV2({
                        id: _fpisLockInfo.id,
                        index: _fpisLockInfo.index,
                        amount: _fpisLockInfo.amount,
                        end: _fpisLockInfo.end,
                        location: address(fpisLocker),
                        estimatedCurrLockVeFXS: _estimatedVeFXS
                    });

                    // Increase the active lock index
                    ++_activeLockIdx;
                }

                unchecked {
                    ++i;
                }
            }
        }

        // (Optional) L1VeFXS
        // -------------------------
        if ((address(l1veFXS) != address(0)) && (address(l1VeFXSTotalSupplyOracle) != address(0))) {
            // Get the LockedBalance
            IL1VeFXS.LockedBalance memory _l1LockedBalance = l1veFXS.locked(_account);

            // Convert to LockedBalanceExtendedV2 and push into _currCombinedLockBalExtds if it is active. There is only one lock too
            if (_l1LockedBalance.end > block.timestamp) {
                // (Optional) Estimate the lock's veFXS based on amount, end, and block.timestamp
                uint256 _estimatedVeFXS;
                if (_estimateCrudeVeFXS) {
                    _estimatedVeFXS = l1veFXS.balanceOf(_account);
                }

                // Add to the temp array
                _tmpActiveLocks[_activeLockIdx] = LockedBalanceExtendedV2({
                    id: 0,
                    index: 0,
                    amount: int128(_l1LockedBalance.amount),
                    end: _l1LockedBalance.end,
                    location: address(l1veFXS),
                    estimatedCurrLockVeFXS: _estimatedVeFXS
                });

                // Increase the active lock index
                ++_activeLockIdx;
            }
        }

        // (Optional) Look in the extra veFXS sources next. They should all be IVestedFXS ABI compliant
        for (uint256 i; i < addlVeContractsArr.length; ) {
            address _veAddr = addlVeContractsArr[i];
            if (_veAddr != address(0)) {
                // Get the active locks
                LockedBalanceExtended[] memory _addlVeFXSLockedBalExtds = (
                    IVestedFXSUtils(IVestedFXS(_veAddr).veFxsUtils()).getDetailedUserLockInfo(_account)
                ).activeLocks;

                // Loop though the active locks and add them to the combined array
                for (uint256 j; j < _addlVeFXSLockedBalExtds.length; ) {
                    // Save tmp variable to memory
                    IveFXSStructs.LockedBalanceExtended memory _addVeFXSLockInfo = _addlVeFXSLockedBalExtds[j];

                    // (Optional) Estimate the lock's veFXS based on amount, end, and block.timestamp
                    uint256 _estimatedVeFXS;
                    if (_estimateCrudeVeFXS) {
                        _estimatedVeFXS = IVestedFXSUtils(IVestedFXS(_veAddr).veFxsUtils())
                            .getCrudeExpectedVeFXSOneLock(
                                _addVeFXSLockInfo.amount,
                                _addVeFXSLockInfo.end - uint128(block.timestamp)
                            );
                    }

                    // Add to the temporary array
                    _tmpActiveLocks[_activeLockIdx] = LockedBalanceExtendedV2({
                        id: _addVeFXSLockInfo.id,
                        index: _addVeFXSLockInfo.index,
                        amount: _addVeFXSLockInfo.amount,
                        end: _addVeFXSLockInfo.end,
                        location: _veAddr,
                        estimatedCurrLockVeFXS: _estimatedVeFXS
                    });

                    // Increase the active lock index
                    ++_activeLockIdx;

                    unchecked {
                        ++j;
                    }
                }
            }

            unchecked {
                ++i;
            }
        }

        // Allocate the return array with only the number of active locks
        _currActiveLocks = new LockedBalanceExtendedV2[](_activeLockIdx);

        // Fill the return array
        for (uint256 i; i < _currActiveLocks.length; ) {
            _currActiveLocks[i] = _tmpActiveLocks[i];

            unchecked {
                ++i;
            }
        }
    }

    /// @notice Get all the expired locks for a user
    /// @param _account The account to get the locks for
    /// @return _expiredLocks Array of LockedBalanceExtendedV2 structs (all expired locks)
    /// @dev Technically could combine with getAllCurrActiveLocks to save gas, but getAllExpiredLocks is mainly intended for a UI
    function getAllExpiredLocks(address _account) public view returns (LockedBalanceExtendedV2[] memory _expiredLocks) {
        // Prepare to allocate the return array. Not all of the locks will be expired.

        // OG 3 veFXS contracts
        // ===================================
        // Fraxtal VestedFXS
        uint256 _maxArrSize = veFXS.numLocks(_account);

        // (Optional) FPIS Locker
        if (address(fpisLocker) != address(0)) _maxArrSize += fpisLocker.numLocks(_account);

        // (Optional) L1VeFXS
        if ((address(l1veFXS) != address(0)) && (address(l1VeFXSTotalSupplyOracle) != address(0))) {
            _maxArrSize += 1; // Legacy veFXS on Mainnet only has one lock
        }

        // (Optional) Get the total number of locks in the additional veFXS contracts
        for (uint256 i = 0; i < addlVeContractsArr.length; i++) {
            address _veAddr = addlVeContractsArr[i];
            if (_veAddr != address(0)) {
                // Get the total number of locks
                _maxArrSize += IVestedFXS(_veAddr).numLocks(_account);
            }
        }

        // Allocate a temporary dynamic array
        uint256 _expiredLockIdx = 0;
        LockedBalanceExtendedV2[] memory _tmpExpiredLocks = new LockedBalanceExtendedV2[](_maxArrSize);

        // Go through the OG 3 sources first

        // Fraxtal veFXS
        // -------------------------
        {
            // Get the LockedBalanceExtendeds
            LockedBalanceExtended[] memory _fxtlVeFXSLockedBalExtds = (veFXSUtils.getDetailedUserLockInfo(_account))
                .expiredLocks;

            // Loop though the Fraxtal veFXS locks and add them to the combined array
            for (uint256 i; i < _fxtlVeFXSLockedBalExtds.length; ) {
                // Save tmp variable to memory
                IveFXSStructs.LockedBalanceExtended memory _vestedFXSLockInfo = _fxtlVeFXSLockedBalExtds[i];

                // Add to the temp array
                _tmpExpiredLocks[_expiredLockIdx] = LockedBalanceExtendedV2({
                    id: _vestedFXSLockInfo.id,
                    index: _vestedFXSLockInfo.index,
                    amount: _vestedFXSLockInfo.amount,
                    end: _vestedFXSLockInfo.end,
                    location: address(veFXS),
                    estimatedCurrLockVeFXS: 0
                });

                // Increase the expired lock index
                ++_expiredLockIdx;

                unchecked {
                    ++i;
                }
            }
        }

        // (Optional) FPIS Locker
        // -------------------------
        if (address(fpisLocker) != address(0)) {
            // Get the LockedBalanceExtendeds
            IlFPISStructs.LockedBalanceExtended[] memory _fpisLockerLockedBalExtds = (
                lFpisUtils.getDetailedUserLockInfo(_account)
            ).expiredLocks;

            // Loop though the FPIS Locker locks and add them to the combined array
            for (uint256 i; i < _fpisLockerLockedBalExtds.length; ) {
                // Save tmp variable to memory
                IlFPISStructs.LockedBalanceExtended memory _fpisLockInfo = _fpisLockerLockedBalExtds[i];

                // Need to save as LockedBalanceExtendedV2
                _tmpExpiredLocks[_expiredLockIdx] = LockedBalanceExtendedV2({
                    id: _fpisLockInfo.id,
                    index: _fpisLockInfo.index,
                    amount: _fpisLockInfo.amount,
                    end: _fpisLockInfo.end,
                    location: address(fpisLocker),
                    estimatedCurrLockVeFXS: 0
                });

                // Increase the expired lock index
                ++_expiredLockIdx;

                unchecked {
                    ++i;
                }
            }
        }

        // (Optional) L1VeFXS
        // -------------------------
        if ((address(l1veFXS) != address(0)) && (address(l1VeFXSTotalSupplyOracle) != address(0))) {
            // Get the LockedBalance
            IL1VeFXS.LockedBalance memory _l1LockedBalance = l1veFXS.locked(_account);

            // Convert to LockedBalanceExtendedV2 and push into _currCombinedLockBalExtds if it is expired. There is only one lock too
            if (_l1LockedBalance.end <= block.timestamp) {
                // Add to the temp array
                _tmpExpiredLocks[_expiredLockIdx] = LockedBalanceExtendedV2({
                    id: 0,
                    index: 0,
                    amount: int128(_l1LockedBalance.amount),
                    end: _l1LockedBalance.end,
                    location: address(l1veFXS),
                    estimatedCurrLockVeFXS: 0
                });

                // Increase the expired lock index
                ++_expiredLockIdx;
            }
        }

        // (Optional) Look in the extra veFXS sources next. They should all be IVestedFXS ABI compliant
        for (uint256 i; i < addlVeContractsArr.length; ) {
            address _veAddr = addlVeContractsArr[i];
            if (_veAddr != address(0)) {
                // Get the expired locks
                LockedBalanceExtended[] memory _addlVeFXSLockedBalExtds = (
                    IVestedFXSUtils(IVestedFXS(_veAddr).veFxsUtils()).getDetailedUserLockInfo(_account)
                ).expiredLocks;

                // Loop though the expired locks and add them to the combined array
                for (uint256 j; j < _addlVeFXSLockedBalExtds.length; ) {
                    // Save tmp variable to memory
                    IveFXSStructs.LockedBalanceExtended memory _addVeFXSLockInfo = _addlVeFXSLockedBalExtds[j];

                    // Add to the temporary array
                    _tmpExpiredLocks[_expiredLockIdx] = LockedBalanceExtendedV2({
                        id: _addVeFXSLockInfo.id,
                        index: _addVeFXSLockInfo.index,
                        amount: _addVeFXSLockInfo.amount,
                        end: _addVeFXSLockInfo.end,
                        location: _veAddr,
                        estimatedCurrLockVeFXS: 0
                    });

                    // Increase the expired lock index
                    ++_expiredLockIdx;

                    unchecked {
                        ++j;
                    }
                }
            }

            unchecked {
                ++i;
            }
        }

        // Allocate the return array with only the number of expired locks
        _expiredLocks = new LockedBalanceExtendedV2[](_expiredLockIdx);

        // Fill the return array
        for (uint256 i; i < _expiredLocks.length; ) {
            _expiredLocks[i] = _tmpExpiredLocks[i];

            unchecked {
                ++i;
            }
        }
    }

    // ==============================================================================
    // MUTATIVE FUNCTIONS
    // ==============================================================================

    // None...

    // ==============================================================================
    // RESTRICTED FUNCTIONS
    // ==============================================================================

    /// @notice Adds an additional veFXS-like contract
    /// @param _addr The contract to added
    function addAddlVeFXSContract(address _addr) public onlyByOwnGov {
        require(_addr != address(0), "Zero address detected");

        // Check the ABI here to make sure it is veFXS-like
        // None of these should revert
        IVestedFXS(_addr).totalSupply();
        IVestedFXS(_addr).balanceOf(address(0));
        IVestedFXS(_addr).numLocks(address(0));
        IVestedFXSUtils(IVestedFXS(_addr).veFxsUtils()).getDetailedUserLockInfo(address(0));
        IVestedFXSUtils(IVestedFXS(_addr).veFxsUtils()).getCrudeExpectedVeFXSOneLock(1e18, 604_800);

        require(addlVeContracts[_addr] == false, "Address already exists");
        addlVeContracts[_addr] = true;
        addlVeContractsArr.push(_addr);

        emit AddlVeFXSContractAdded(_addr);
    }

    /// @notice Removes a veFXS-like contract. Will need to mass checkpoint on the yield distributor or other sources to reflect new stored total veFXS
    /// @param _addr The contract to remove
    function removeAddlVeFXSContract(address _addr) public onlyByOwnGov {
        require(_addr != address(0), "Zero address detected");
        require(addlVeContracts[_addr] == true, "Address nonexistent");

        // Delete from the mapping
        delete addlVeContracts[_addr];

        // 'Delete' from the array by setting the address to 0x0
        for (uint256 i = 0; i < addlVeContractsArr.length; i++) {
            if (addlVeContractsArr[i] == _addr) {
                addlVeContractsArr[i] = address(0); // This will leave a null in the array and keep the indices the same
                break;
            }
        }

        emit AddlVeFXSContractRemoved(_addr);
    }

    /// @notice Added to support recovering LP Yield and other mistaken tokens from other systems to be distributed to holders
    /// @param _tokenAddress The token to recover
    /// @param _tokenAmount The amount to recover
    function recoverERC20(address _tokenAddress, uint256 _tokenAmount) external onlyByOwnGov {
        // Only the owner address can ever receive the recovery withdrawal
        TransferHelper.safeTransfer(_tokenAddress, owner, _tokenAmount);
        emit RecoveredERC20(_tokenAddress, _tokenAmount);
    }

    /// @notice Set the original 3 veFXS-like contracts on Fraxtal
    /// @param _veAddresses The addresses: 0: veFXS, 1: veFXSUtils, 2: FPIS Locker, 3: FPISLockerUtils, 4: L1VeFXS, 5: L1VeFXSTotalSupplyOracle
    function setAddresses(address[6] calldata _veAddresses) external onlyByOwnGov {
        // Future upgrade: remove this once full support is added and tested
        require(_veAddresses[0] != address(0), "veFXS must not be 0x0");
        require(_veAddresses[1] != address(0), "veFXSUtils must not be 0x0");
        require(_veAddresses[2] != address(0), "Cannot add FPISLocker yet");
        require(_veAddresses[3] != address(0), "Cannot add FPISLockerUtils yet");
        require(_veAddresses[4] != address(0), "Cannot add L1VeFXS yet");
        require(_veAddresses[5] != address(0), "Cannot add L1VeFXSTotalSupplyOracle yet");

        // Set veFXS-like addresses
        veFXS = IVestedFXS(_veAddresses[0]);
        veFXSUtils = IVestedFXSUtils(_veAddresses[1]);

        // FPIS Locker
        if ((_veAddresses[2] != address(0)) && _veAddresses[3] != address(0)) {
            fpisLocker = IFPISLocker(_veAddresses[2]);
            lFpisUtils = FPISLockerUtils(_veAddresses[3]);
        }

        // L1VeFXS and L1VeFXSTotalSupplyOracle
        if ((_veAddresses[4] != address(0)) && (_veAddresses[5] != address(0))) {
            l1veFXS = IL1VeFXS(_veAddresses[4]);
            l1VeFXSTotalSupplyOracle = L1VeFXSTotalSupplyOracle(_veAddresses[5]);
        }
    }

    /// @notice Set the timelock address
    /// @param _newTimelock The address of the timelock
    function setTimelock(address _newTimelock) external onlyByOwnGov {
        timelockAddress = _newTimelock;
    }

    // ==============================================================================
    // EVENTS
    // ==============================================================================

    /// @notice When an additional veFXS contract is added
    /// @param addr The contract that was added
    event AddlVeFXSContractAdded(address addr);

    /// @notice When an additional veFXS contract is removed
    /// @param addr The contract that was removed
    event AddlVeFXSContractRemoved(address addr);

    /// @notice When the contract is initialized
    event DefaultInitialization();

    /// @notice When ERC20 tokens were recovered
    /// @param token Token address
    /// @param amount Amount of tokens collected
    event RecoveredERC20(address token, uint256 amount);

    /// @notice When a reward is deposited
    /// @param reward Amount of tokens deposited
    /// @param yieldRate The resultant yield/emission rate
    event RewardAdded(uint256 reward, uint256 yieldRate);

    /// @notice When yield is collected
    /// @param user Address collecting the yield
    /// @param yield The amount of tokens collected
    /// @param tokenAddress The address collecting the rewards
    event YieldCollected(address indexed user, uint256 yield, address tokenAddress);

    /// @notice When the yield duration is updated
    /// @param newDuration The new duration
    event YieldDurationUpdated(uint256 newDuration);

    // ==============================================================================
    // ERRORS
    // ==============================================================================

    /// @notice Cannot initialize twice
    error InitializeFailed();

    /// @notice If you are trying to call a function not as the owner or timelock
    error NotOwnerOrTimelock();
}

Contract Security Audit

Contract ABI

API
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"InitializeFailed","type":"error"},{"inputs":[],"name":"InvalidOwnershipAcceptance","type":"error"},{"inputs":[],"name":"NotOwnerOrTimelock","type":"error"},{"inputs":[],"name":"OnlyOwner","type":"error"},{"inputs":[],"name":"OwnerCannotBeZero","type":"error"},{"inputs":[],"name":"TransferHelperTransferFailed","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"addr","type":"address"}],"name":"AddlVeFXSContractAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"addr","type":"address"}],"name":"AddlVeFXSContractRemoved","type":"event"},{"anonymous":false,"inputs":[],"name":"DefaultInitialization","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerNominated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RecoveredERC20","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"yieldRate","type":"uint256"}],"name":"RewardAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"yield","type":"uint256"},{"indexed":false,"internalType":"address","name":"tokenAddress","type":"address"}],"name":"YieldCollected","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newDuration","type":"uint256"}],"name":"YieldDurationUpdated","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_addr","type":"address"}],"name":"addAddlVeFXSContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"addlVeContracts","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"addlVeContractsArr","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"allAddlVeContractsAddreses","outputs":[{"internalType":"address[]","name":"_addresses","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"allAddlVeContractsLength","outputs":[{"internalType":"uint256","name":"_length","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fpisLocker","outputs":[{"internalType":"contract IFPISLocker","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"bool","name":"_estimateCrudeVeFXS","type":"bool"}],"name":"getAllCurrActiveLocks","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint128","name":"index","type":"uint128"},{"internalType":"int128","name":"amount","type":"int128"},{"internalType":"uint128","name":"end","type":"uint128"},{"internalType":"address","name":"location","type":"address"},{"internalType":"uint256","name":"estimatedCurrLockVeFXS","type":"uint256"}],"internalType":"struct IveFXSStructs.LockedBalanceExtendedV2[]","name":"_currActiveLocks","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"getAllExpiredLocks","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint128","name":"index","type":"uint128"},{"internalType":"int128","name":"amount","type":"int128"},{"internalType":"uint128","name":"end","type":"uint128"},{"internalType":"address","name":"location","type":"address"},{"internalType":"uint256","name":"estimatedCurrLockVeFXS","type":"uint256"}],"internalType":"struct IveFXSStructs.LockedBalanceExtendedV2[]","name":"_expiredLocks","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_timelockAddress","type":"address"},{"internalType":"address[6]","name":"_veAddresses","type":"address[6]"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"l1VeFXSTotalSupplyOracle","outputs":[{"internalType":"contract L1VeFXSTotalSupplyOracle","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"l1veFXS","outputs":[{"internalType":"contract IL1VeFXS","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lFpisUtils","outputs":[{"internalType":"contract FPISLockerUtils","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"nominateNewOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nominatedOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"uint256","name":"_tokenAmount","type":"uint256"}],"name":"recoverERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_addr","type":"address"}],"name":"removeAddlVeFXSContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[6]","name":"_veAddresses","type":"address[6]"}],"name":"setAddresses","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newTimelock","type":"address"}],"name":"setTimelock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"timelockAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"ttlCombinedVeFXS","outputs":[{"internalType":"uint256","name":"_currBal","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ttlCombinedVeFXSTotalSupply","outputs":[{"internalType":"uint256","name":"_totalSupply","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ttlCombinedVeFXSTotalSupplyDetailed","outputs":[{"components":[{"internalType":"uint256","name":"vestedFXSTotal","type":"uint256"},{"internalType":"uint256","name":"fpisLockerTotal","type":"uint256"},{"internalType":"uint256","name":"l1veFXSTotal","type":"uint256"},{"internalType":"uint256","name":"otherSourcesTotal","type":"uint256"},{"internalType":"uint256","name":"grandTotal","type":"uint256"}],"internalType":"struct VeFXSAggregator.DetailedTotalSupplyInfo","name":"_supplyInfo","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"veFXS","outputs":[{"internalType":"contract IVestedFXS","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"veFXSUtils","outputs":[{"internalType":"contract IVestedFXSUtils","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

6080604052348015600e575f80fd5b505f80546001600160a01b0319163390811782556040805192835260208301919091527fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c910160405180910390a160016002819055600c805460ff191690911790556144548061007d5f395ff3fe608060405234801561000f575f80fd5b50600436106101a5575f3560e01c806379ba5097116100e8578063c0f456bd11610093578063f0657ab61161006e578063f0657ab614610429578063f21b723514610431578063f5d812cb14610444578063f868139b14610464575f80fd5b8063c0f456bd146103e4578063d96658d9146103f6578063ee73e04614610409575f80fd5b80638da5cb5b116100c35780638da5cb5b1461039f578063a6bffe7b146103be578063bdacb303146103d1575f80fd5b806379ba5097146103645780637eb1554e1461036c5780638980f11f1461038c575f80fd5b80634bc66f3211610153578063576221561161012e57806357622156146102d55780637351bf96146102e8578063744f008d146102fb5780637873fae614610344575f80fd5b80634bc66f3214610280578063525456d2146102a057806353a47bb7146102b5575f80fd5b80631627540c116101835780631627540c1461021b57806319ff52fd1461022e5780632f9b12f81461024e575f80fd5b806303d8477f146101a9578063054d2d1e146101be57806314b64f7c146101d1575b5f80fd5b6101bc6101b7366004613cbe565b610484565b005b6101bc6101cc366004613cfe565b610b34565b6008546101f19073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6101bc610229366004613cfe565b611146565b6003546101f19073ffffffffffffffffffffffffffffffffffffffff1681565b61027061025c366004613cfe565b600b6020525f908152604090205460ff1681565b6040519015158152602001610212565b6009546101f19073ffffffffffffffffffffffffffffffffffffffff1681565b6102a8611209565b6040516102129190613d20565b6001546101f19073ffffffffffffffffffffffffffffffffffffffff1681565b6101f16102e3366004613d78565b611276565b6101bc6102f6366004613e34565b6112ab565b610303611491565b60405161021291905f60a082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015292915050565b6004546101f19073ffffffffffffffffffffffffffffffffffffffff1681565b6101bc6117fe565b61037f61037a366004613ecf565b6118f1565b6040516102129190613f06565b6101bc61039a366004613fb4565b612829565b5f546101f19073ffffffffffffffffffffffffffffffffffffffff1681565b61037f6103cc366004613cfe565b612916565b6101bc6103df366004613cfe565b6134ac565b600a545b604051908152602001610212565b6103e8610404366004613cfe565b613569565b6005546101f19073ffffffffffffffffffffffffffffffffffffffff1681565b6103e8613892565b6101bc61043f366004613cfe565b6138a6565b6006546101f19073ffffffffffffffffffffffffffffffffffffffff1681565b6007546101f19073ffffffffffffffffffffffffffffffffffffffff1681565b5f5473ffffffffffffffffffffffffffffffffffffffff1633148015906104c3575060095473ffffffffffffffffffffffffffffffffffffffff163314155b156104fa576040517ffee4291a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6105086020830183613cfe565b73ffffffffffffffffffffffffffffffffffffffff160361058a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f7665465853206d757374206e6f7420626520307830000000000000000000000060448201526064015b60405180910390fd5b5f61059b6040830160208401613cfe565b73ffffffffffffffffffffffffffffffffffffffff1603610618576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f76654658535574696c73206d757374206e6f74206265203078300000000000006044820152606401610581565b5f6106296060830160408401613cfe565b73ffffffffffffffffffffffffffffffffffffffff16036106a6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f43616e6e6f742061646420465049534c6f636b657220796574000000000000006044820152606401610581565b5f6106b76080830160608401613cfe565b73ffffffffffffffffffffffffffffffffffffffff1603610734576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f43616e6e6f742061646420465049534c6f636b65725574696c732079657400006044820152606401610581565b5f61074560a0830160808401613cfe565b73ffffffffffffffffffffffffffffffffffffffff16036107c2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f43616e6e6f7420616464204c31566546585320796574000000000000000000006044820152606401610581565b5f6107d360c0830160a08401613cfe565b73ffffffffffffffffffffffffffffffffffffffff1603610876576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f43616e6e6f7420616464204c315665465853546f74616c537570706c794f726160448201527f636c6520796574000000000000000000000000000000000000000000000000006064820152608401610581565b6108836020820182613cfe565b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff929092169190911790556108d86040820160208301613cfe565b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff929092169190911790555f61092e6060830160408401613cfe565b73ffffffffffffffffffffffffffffffffffffffff161415801561097757505f61095e6080830160608401613cfe565b73ffffffffffffffffffffffffffffffffffffffff1614155b15610a275761098c6060820160408301613cfe565b600480547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff929092169190911790556109e16080820160608301613cfe565b600780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff929092169190911790555b5f610a3860a0830160808401613cfe565b73ffffffffffffffffffffffffffffffffffffffff1614158015610a8157505f610a6860c0830160a08401613cfe565b73ffffffffffffffffffffffffffffffffffffffff1614155b15610b3157610a9660a0820160808301613cfe565b600580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055610aeb60c0820160a08301613cfe565b600880547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff929092169190911790555b50565b5f5473ffffffffffffffffffffffffffffffffffffffff163314801590610b73575060095473ffffffffffffffffffffffffffffffffffffffff163314155b15610baa576040517ffee4291a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8116610c27576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f5a65726f206164647265737320646574656374656400000000000000000000006044820152606401610581565b8073ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c70573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c94919061400b565b506040517f70a082310000000000000000000000000000000000000000000000000000000081525f600482015273ffffffffffffffffffffffffffffffffffffffff8216906370a0823190602401602060405180830381865afa158015610cfd573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d21919061400b565b506040517fb9ef08300000000000000000000000000000000000000000000000000000000081525f600482015273ffffffffffffffffffffffffffffffffffffffff82169063b9ef083090602401602060405180830381865afa158015610d8a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610dae9190614046565b508073ffffffffffffffffffffffffffffffffffffffff166366d6bff96040518163ffffffff1660e01b8152600401602060405180830381865afa158015610df8573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e1c919061406a565b6040517f3c5933120000000000000000000000000000000000000000000000000000000081525f600482015273ffffffffffffffffffffffffffffffffffffffff9190911690633c593312906024015f60405180830381865afa158015610e85573d5f803e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610eca91908101906141d5565b508073ffffffffffffffffffffffffffffffffffffffff166366d6bff96040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f14573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f38919061406a565b6040517f0c8d01e6000000000000000000000000000000000000000000000000000000008152670de0b6b3a7640000600482015262093a80602482015273ffffffffffffffffffffffffffffffffffffffff9190911690630c8d01e690604401602060405180830381865afa158015610fb3573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610fd7919061400b565b5073ffffffffffffffffffffffffffffffffffffffff81165f908152600b602052604090205460ff1615611067576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4164647265737320616c726561647920657869737473000000000000000000006044820152606401610581565b73ffffffffffffffffffffffffffffffffffffffff81165f818152600b6020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001908117909155600a805491820181559093527fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a890920180547fffffffffffffffffffffffff0000000000000000000000000000000000000000168417905590519182527f75ccbc951feec3500ed75b1652ef72542006274e6f34d220bc70e3342fce797e91015b60405180910390a150565b5f5473ffffffffffffffffffffffffffffffffffffffff163314611196576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce229060200161113b565b6060600a80548060200260200160405190810160405280929190818152602001828054801561126c57602002820191905f5260205f20905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311611241575b5050505050905090565b600a8181548110611285575f80fd5b5f9182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b600c5460ff16156112e8576040517fd08e7ac200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805473ffffffffffffffffffffffffffffffffffffffff8581167fffffffffffffffffffffffff000000000000000000000000000000000000000092831617909255600980548584169083161790558251600380548316918416919091179055602083015160068054909216908316179055604082015116158015906113885750606081015173ffffffffffffffffffffffffffffffffffffffff1615155b156113e95760408101516004805473ffffffffffffffffffffffffffffffffffffffff9283167fffffffffffffffffffffffff0000000000000000000000000000000000000000918216179091556060830151600780549190931691161790555b608081015173ffffffffffffffffffffffffffffffffffffffff161580159061142b575060a081015173ffffffffffffffffffffffffffffffffffffffff1615155b1561148c5760808101516005805473ffffffffffffffffffffffffffffffffffffffff9283167fffffffffffffffffffffffff00000000000000000000000000000000000000009182161790915560a0830151600880549190931691161790555b505050565b6114be6040518060a001604052805f81526020015f81526020015f81526020015f81526020015f81525090565b60035f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611528573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061154c919061400b565b808252608082015260045473ffffffffffffffffffffffffffffffffffffffff161561161d5760048054604080517f18160ddd000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff909216926318160ddd9282820192602092908290030181865afa1580156115dd573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611601919061400b565b602082018190526080820180516116199083906142f2565b9052505b60055473ffffffffffffffffffffffffffffffffffffffff161580159061165b575060085473ffffffffffffffffffffffffffffffffffffffff1615155b1561170a5760085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156116ca573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116ee919061400b565b604082018190526080820180516117069083906142f2565b9052505b5f5b600a548110156117fa575f600a828154811061172a5761172a613fde565b5f9182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905080156117f1575f8173ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561179d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117c1919061400b565b905080846060018181516117d591906142f2565b9052506080840180518291906117ec9083906142f2565b905250505b5060010161170c565b5090565b60015473ffffffffffffffffffffffffffffffffffffffff16331461184f576040517fd74b334e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f546001546040805173ffffffffffffffffffffffffffffffffffffffff93841681529290911660208301527fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c910160405180910390a1600180545f80547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff841617909155169055565b6003546040517fb9ef083000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301526060925f9291169063b9ef083090602401602060405180830381865afa158015611963573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119879190614046565b6004546fffffffffffffffffffffffffffffffff91909116915073ffffffffffffffffffffffffffffffffffffffff1615611a6f57600480546040517fb9ef083000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8781169382019390935291169063b9ef083090602401602060405180830381865afa158015611a2c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a509190614046565b611a6c906fffffffffffffffffffffffffffffffff16826142f2565b90505b60055473ffffffffffffffffffffffffffffffffffffffff1615801590611aad575060085473ffffffffffffffffffffffffffffffffffffffff1615155b15611ac057611abd6001826142f2565b90505b5f5b600a54811015611bbf575f600a8281548110611ae057611ae0613fde565b5f9182526020909120015473ffffffffffffffffffffffffffffffffffffffff1690508015611bb6576040517fb9ef083000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff878116600483015282169063b9ef083090602401602060405180830381865afa158015611b73573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b979190614046565b611bb3906fffffffffffffffffffffffffffffffff16846142f2565b92505b50600101611ac2565b505f808267ffffffffffffffff811115611bdb57611bdb613d8f565b604051908082528060200260200182016040528015611c5857816020015b6040805160c0810182525f8082526020808301829052928201819052606082018190526080820181905260a082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909201910181611bf95790505b506006546040517f3c59331200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff89811660048301529293505f9290911690633c593312906024015f60405180830381865afa158015611ccb573d5f803e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611d1091908101906141d5565b6060015190505f5b8151811015611ee0575f828281518110611d3457611d34613fde565b602002602001015190505f8815611e10576006546040830151606084015173ffffffffffffffffffffffffffffffffffffffff90921691630c8d01e69190611d7d90429061430b565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152600f9290920b60048301526fffffffffffffffffffffffffffffffff166024820152604401602060405180830381865afa158015611de9573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e0d919061400b565b90505b6040518060c00160405280835f0151815260200183602001516fffffffffffffffffffffffffffffffff1681526020018360400151600f0b815260200183606001516fffffffffffffffffffffffffffffffff16815260200160035f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815250858781518110611ebc57611ebc613fde565b602002602001018190525085611ed190614333565b95508260010192505050611d18565b505060045473ffffffffffffffffffffffffffffffffffffffff16156121a1576007546040517f3c59331200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff88811660048301525f921690633c593312906024015f60405180830381865afa158015611f6d573d5f803e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611fb291908101906141d5565b6060015190505f5b815181101561219e575f828281518110611fd657611fd6613fde565b602002602001015190504281606001516fffffffffffffffffffffffffffffffff161115612195575f88156120d0576007546040830151606084015173ffffffffffffffffffffffffffffffffffffffff90921691630e5f6d5d919061203d90429061430b565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152600f9290920b60048301526fffffffffffffffffffffffffffffffff166024820152604401602060405180830381865afa1580156120a9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120cd919061400b565b90505b6040518060c00160405280835f0151815260200183602001516fffffffffffffffffffffffffffffffff1681526020018360400151600f0b815260200183606001516fffffffffffffffffffffffffffffffff16815260200160045f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281525085878151811061217c5761217c613fde565b60200260200101819052508561219190614333565b9550505b50600101611fba565b50505b60055473ffffffffffffffffffffffffffffffffffffffff16158015906121df575060085473ffffffffffffffffffffffffffffffffffffffff1615155b156123b4576005546040517fcbf9fe5f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff88811660048301525f92169063cbf9fe5f90602401606060405180830381865afa158015612252573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906122769190614381565b905042816020015167ffffffffffffffff1611156123b2575f861561232a576005546040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a81166004830152909116906370a0823190602401602060405180830381865afa158015612303573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612327919061400b565b90505b6040805160c0810182525f8082526020808301919091528451600f0b928201929092529083015167ffffffffffffffff16606082015260055473ffffffffffffffffffffffffffffffffffffffff16608082015260a08101829052835184908690811061239957612399613fde565b6020026020010181905250836123ae90614333565b9350505b505b5f5b600a5481101561273b575f600a82815481106123d4576123d4613fde565b5f9182526020909120015473ffffffffffffffffffffffffffffffffffffffff1690508015612732575f8173ffffffffffffffffffffffffffffffffffffffff166366d6bff96040518163ffffffff1660e01b8152600401602060405180830381865afa158015612447573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061246b919061406a565b6040517f3c59331200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8b811660048301529190911690633c593312906024015f60405180830381865afa1580156124d6573d5f803e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261251b91908101906141d5565b6060015190505f5b815181101561272f575f82828151811061253f5761253f613fde565b602002602001015190505f8a15612680578473ffffffffffffffffffffffffffffffffffffffff166366d6bff96040518163ffffffff1660e01b8152600401602060405180830381865afa158015612599573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906125bd919061406a565b73ffffffffffffffffffffffffffffffffffffffff16630c8d01e683604001514285606001516125ed919061430b565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152600f9290920b60048301526fffffffffffffffffffffffffffffffff166024820152604401602060405180830381865afa158015612659573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061267d919061400b565b90505b6040518060c00160405280835f0151815260200183602001516fffffffffffffffffffffffffffffffff1681526020018360400151600f0b815260200183606001516fffffffffffffffffffffffffffffffff1681526020018673ffffffffffffffffffffffffffffffffffffffff1681526020018281525087898151811061270b5761270b613fde565b60200260200101819052508761272090614333565b97508260010192505050612523565b50505b506001016123b6565b508167ffffffffffffffff81111561275557612755613d8f565b6040519080825280602002602001820160405280156127d257816020015b6040805160c0810182525f8082526020808301829052928201819052606082018190526080820181905260a082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816127735790505b5093505f5b845181101561281f578181815181106127f2576127f2613fde565b602002602001015185828151811061280c5761280c613fde565b60209081029190910101526001016127d7565b5050505092915050565b5f5473ffffffffffffffffffffffffffffffffffffffff163314801590612868575060095473ffffffffffffffffffffffffffffffffffffffff163314155b1561289f576040517ffee4291a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f546128c390839073ffffffffffffffffffffffffffffffffffffffff1683613b7e565b6040805173ffffffffffffffffffffffffffffffffffffffff84168152602081018390527f55350610fe57096d8c0ffa30beede987326bccfcb0b4415804164d0dd50ce8b1910160405180910390a15050565b6003546040517fb9ef083000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301526060925f9291169063b9ef083090602401602060405180830381865afa158015612988573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906129ac9190614046565b6004546fffffffffffffffffffffffffffffffff91909116915073ffffffffffffffffffffffffffffffffffffffff1615612a9457600480546040517fb9ef083000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8681169382019390935291169063b9ef083090602401602060405180830381865afa158015612a51573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612a759190614046565b612a91906fffffffffffffffffffffffffffffffff16826142f2565b90505b60055473ffffffffffffffffffffffffffffffffffffffff1615801590612ad2575060085473ffffffffffffffffffffffffffffffffffffffff1615155b15612ae557612ae26001826142f2565b90505b5f5b600a54811015612be4575f600a8281548110612b0557612b05613fde565b5f9182526020909120015473ffffffffffffffffffffffffffffffffffffffff1690508015612bdb576040517fb9ef083000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff868116600483015282169063b9ef083090602401602060405180830381865afa158015612b98573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612bbc9190614046565b612bd8906fffffffffffffffffffffffffffffffff16846142f2565b92505b50600101612ae7565b505f808267ffffffffffffffff811115612c0057612c00613d8f565b604051908082528060200260200182016040528015612c7d57816020015b6040805160c0810182525f8082526020808301829052928201819052606082018190526080820181905260a082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909201910181612c1e5790505b506006546040517f3c59331200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff88811660048301529293505f9290911690633c593312906024015f60405180830381865afa158015612cf0573d5f803e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612d3591908101906141d5565b6080015190505f5b8151811015612e2f575f828281518110612d5957612d59613fde565b602002602001015190506040518060c00160405280825f0151815260200182602001516fffffffffffffffffffffffffffffffff1681526020018260400151600f0b815260200182606001516fffffffffffffffffffffffffffffffff16815260200160035f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020015f815250848681518110612e0f57612e0f613fde565b602002602001018190525084612e2490614333565b945050600101612d3d565b505060045473ffffffffffffffffffffffffffffffffffffffff1615612ffe576007546040517f3c59331200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87811660048301525f921690633c593312906024015f60405180830381865afa158015612ebc573d5f803e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612f0191908101906141d5565b6080015190505f5b8151811015612ffb575f828281518110612f2557612f25613fde565b602002602001015190506040518060c00160405280825f0151815260200182602001516fffffffffffffffffffffffffffffffff1681526020018260400151600f0b815260200182606001516fffffffffffffffffffffffffffffffff16815260200160045f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020015f815250848681518110612fdb57612fdb613fde565b602002602001018190525084612ff090614333565b945050600101612f09565b50505b60055473ffffffffffffffffffffffffffffffffffffffff161580159061303c575060085473ffffffffffffffffffffffffffffffffffffffff1615155b15613173576005546040517fcbf9fe5f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87811660048301525f92169063cbf9fe5f90602401606060405180830381865afa1580156130af573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906130d39190614381565b905042816020015167ffffffffffffffff1611613171576040805160c0810182525f80825260208083018290528451600f0b938301939093529183015167ffffffffffffffff16606082015260055473ffffffffffffffffffffffffffffffffffffffff16608082015260a0810191909152825183908590811061315957613159613fde565b60200260200101819052508261316e90614333565b92505b505b5f5b600a548110156133bf575f600a828154811061319357613193613fde565b5f9182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905080156133b6575f8173ffffffffffffffffffffffffffffffffffffffff166366d6bff96040518163ffffffff1660e01b8152600401602060405180830381865afa158015613206573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061322a919061406a565b6040517f3c59331200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a811660048301529190911690633c593312906024015f60405180830381865afa158015613295573d5f803e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526132da91908101906141d5565b6080015190505f5b81518110156133b3575f8282815181106132fe576132fe613fde565b602002602001015190506040518060c00160405280825f0151815260200182602001516fffffffffffffffffffffffffffffffff1681526020018260400151600f0b815260200182606001516fffffffffffffffffffffffffffffffff1681526020018573ffffffffffffffffffffffffffffffffffffffff1681526020015f81525086888151811061339357613393613fde565b6020026020010181905250866133a890614333565b9650506001016132e2565b50505b50600101613175565b508167ffffffffffffffff8111156133d9576133d9613d8f565b60405190808252806020026020018201604052801561345657816020015b6040805160c0810182525f8082526020808301829052928201819052606082018190526080820181905260a082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816133f75790505b5093505f5b84518110156134a35781818151811061347657613476613fde565b602002602001015185828151811061349057613490613fde565b602090810291909101015260010161345b565b50505050919050565b5f5473ffffffffffffffffffffffffffffffffffffffff1633148015906134eb575060095473ffffffffffffffffffffffffffffffffffffffff163314155b15613522576040517ffee4291a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600980547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6003546040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301525f9216906370a0823190602401602060405180830381865afa1580156135d7573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906135fb919061400b565b60045490915073ffffffffffffffffffffffffffffffffffffffff16156136bd57600480546040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff858116938201939093529116906370a0823190602401602060405180830381865afa15801561368c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906136b0919061400b565b6136ba90826142f2565b90505b60055473ffffffffffffffffffffffffffffffffffffffff16158015906136fb575060085473ffffffffffffffffffffffffffffffffffffffff1615155b1561379f576005546040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152909116906370a0823190602401602060405180830381865afa15801561376e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613792919061400b565b61379c90826142f2565b90505b5f5b600a5481101561388c575f600a82815481106137bf576137bf613fde565b5f9182526020909120015473ffffffffffffffffffffffffffffffffffffffff1690508015613883576040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301528216906370a0823190602401602060405180830381865afa158015613852573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613876919061400b565b61388090846142f2565b92505b506001016137a1565b50919050565b5f8061389c611491565b6080015192915050565b5f5473ffffffffffffffffffffffffffffffffffffffff1633148015906138e5575060095473ffffffffffffffffffffffffffffffffffffffff163314155b1561391c576040517ffee4291a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8116613999576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f5a65726f206164647265737320646574656374656400000000000000000000006044820152606401610581565b73ffffffffffffffffffffffffffffffffffffffff81165f908152600b602052604090205460ff161515600114613a2c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f41646472657373206e6f6e6578697374656e74000000000000000000000000006044820152606401610581565b73ffffffffffffffffffffffffffffffffffffffff81165f908152600b6020526040812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555b600a54811015613b37578173ffffffffffffffffffffffffffffffffffffffff16600a8281548110613aab57613aab613fde565b5f9182526020909120015473ffffffffffffffffffffffffffffffffffffffff1603613b2f575f600a8281548110613ae557613ae5613fde565b905f5260205f20015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550613b37565b600101613a77565b5060405173ffffffffffffffffffffffffffffffffffffffff821681527ff3517f912cde760e82811897047177df419c7aa16326d5710e6b425a8a7d10359060200161113b565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905291515f92839290871691613c1491906143ed565b5f604051808303815f865af19150503d805f8114613c4d576040519150601f19603f3d011682016040523d82523d5f602084013e613c52565b606091505b5091509150811580613c805750805115801590613c80575080806020019051810190613c7e9190614403565b155b15613cb7576040517f19a9708500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b5f60c08284031215613cce575f80fd5b8260c08301111561388c575f80fd5b73ffffffffffffffffffffffffffffffffffffffff81168114610b31575f80fd5b5f60208284031215613d0e575f80fd5b8135613d1981613cdd565b9392505050565b602080825282518282018190525f918401906040840190835b81811015613d6d57835173ffffffffffffffffffffffffffffffffffffffff16835260209384019390920191600101613d39565b509095945050505050565b5f60208284031215613d88575f80fd5b5035919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b60405160c0810167ffffffffffffffff81118282101715613ddf57613ddf613d8f565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613e2c57613e2c613d8f565b604052919050565b5f805f6101008486031215613e47575f80fd5b8335613e5281613cdd565b92506020840135613e6281613cdd565b9150605f84018513613e72575f80fd5b613e7c60c0613de5565b80610100860187811115613e8e575f80fd5b604087015b81811015613eb4578035613ea681613cdd565b845260209384019301613e93565b505080925050509250925092565b8015158114610b31575f80fd5b5f8060408385031215613ee0575f80fd5b8235613eeb81613cdd565b91506020830135613efb81613ec2565b809150509250929050565b602080825282518282018190525f918401906040840190835b81811015613d6d578351805184526fffffffffffffffffffffffffffffffff60208201511660208501526040810151600f0b60408501526fffffffffffffffffffffffffffffffff606082015116606085015273ffffffffffffffffffffffffffffffffffffffff608082015116608085015260a081015160a08501525060c083019250602084019350600181019050613f1f565b5f8060408385031215613fc5575f80fd5b8235613fd081613cdd565b946020939093013593505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f6020828403121561401b575f80fd5b5051919050565b80516fffffffffffffffffffffffffffffffff81168114614041575f80fd5b919050565b5f60208284031215614056575f80fd5b613d1982614022565b805161404181613cdd565b5f6020828403121561407a575f80fd5b8151613d1981613cdd565b8051600f81900b8114614041575f80fd5b5f82601f8301126140a5575f80fd5b8151602083015f8067ffffffffffffffff8411156140c5576140c5613d8f565b60208460051b0190506140d781613de5565b84815260079490941b83019391505060208101868411156140f6575f80fd5b83831015614180575f6080848903121561410e575f80fd5b6040516080810167ffffffffffffffff8111828210171561413157614131613d8f565b6040528451808252915061414760208601614022565b602082015261415860408601614085565b604082015261416960608601614022565b6060820152825250608092909201916020016140f6565b5095945050505050565b5f82601f830112614199575f80fd5b6141a36060613de5565b8060608401858111156141b4575f80fd5b845b81811015613d6d576141c781614085565b8452602093840193016141b6565b5f602082840312156141e5575f80fd5b815167ffffffffffffffff8111156141fb575f80fd5b8201610100818503121561420d575f80fd5b614215613dbc565b61421e8261405f565b815260208281015190820152604082015167ffffffffffffffff811115614243575f80fd5b61424f86828501614096565b604083015250606082015167ffffffffffffffff81111561426e575f80fd5b61427a86828501614096565b606083015250608082015167ffffffffffffffff811115614299575f80fd5b6142a586828501614096565b6080830152506142b88560a0840161418a565b60a0820152949350505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115614305576143056142c5565b92915050565b6fffffffffffffffffffffffffffffffff8281168282160390811115614305576143056142c5565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614363576143636142c5565b5060010190565b805167ffffffffffffffff81168114614041575f80fd5b5f6060828403128015614392575f80fd5b506040516060810167ffffffffffffffff811182821017156143b6576143b6613d8f565b6040526143c283614022565b81526143d06020840161436a565b60208201526143e16040840161436a565b60408201529392505050565b5f82518060208501845e5f920191825250919050565b5f60208284031215614413575f80fd5b8151613d1981613ec256fea2646970667358221220906e77c6f61b3057feae5009f729232e2975ab0fb6ae39d9a4d084df7d210dc164736f6c634300081a0033

Deployed Bytecode

0x608060405234801561000f575f80fd5b50600436106101a5575f3560e01c806379ba5097116100e8578063c0f456bd11610093578063f0657ab61161006e578063f0657ab614610429578063f21b723514610431578063f5d812cb14610444578063f868139b14610464575f80fd5b8063c0f456bd146103e4578063d96658d9146103f6578063ee73e04614610409575f80fd5b80638da5cb5b116100c35780638da5cb5b1461039f578063a6bffe7b146103be578063bdacb303146103d1575f80fd5b806379ba5097146103645780637eb1554e1461036c5780638980f11f1461038c575f80fd5b80634bc66f3211610153578063576221561161012e57806357622156146102d55780637351bf96146102e8578063744f008d146102fb5780637873fae614610344575f80fd5b80634bc66f3214610280578063525456d2146102a057806353a47bb7146102b5575f80fd5b80631627540c116101835780631627540c1461021b57806319ff52fd1461022e5780632f9b12f81461024e575f80fd5b806303d8477f146101a9578063054d2d1e146101be57806314b64f7c146101d1575b5f80fd5b6101bc6101b7366004613cbe565b610484565b005b6101bc6101cc366004613cfe565b610b34565b6008546101f19073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6101bc610229366004613cfe565b611146565b6003546101f19073ffffffffffffffffffffffffffffffffffffffff1681565b61027061025c366004613cfe565b600b6020525f908152604090205460ff1681565b6040519015158152602001610212565b6009546101f19073ffffffffffffffffffffffffffffffffffffffff1681565b6102a8611209565b6040516102129190613d20565b6001546101f19073ffffffffffffffffffffffffffffffffffffffff1681565b6101f16102e3366004613d78565b611276565b6101bc6102f6366004613e34565b6112ab565b610303611491565b60405161021291905f60a082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015292915050565b6004546101f19073ffffffffffffffffffffffffffffffffffffffff1681565b6101bc6117fe565b61037f61037a366004613ecf565b6118f1565b6040516102129190613f06565b6101bc61039a366004613fb4565b612829565b5f546101f19073ffffffffffffffffffffffffffffffffffffffff1681565b61037f6103cc366004613cfe565b612916565b6101bc6103df366004613cfe565b6134ac565b600a545b604051908152602001610212565b6103e8610404366004613cfe565b613569565b6005546101f19073ffffffffffffffffffffffffffffffffffffffff1681565b6103e8613892565b6101bc61043f366004613cfe565b6138a6565b6006546101f19073ffffffffffffffffffffffffffffffffffffffff1681565b6007546101f19073ffffffffffffffffffffffffffffffffffffffff1681565b5f5473ffffffffffffffffffffffffffffffffffffffff1633148015906104c3575060095473ffffffffffffffffffffffffffffffffffffffff163314155b156104fa576040517ffee4291a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6105086020830183613cfe565b73ffffffffffffffffffffffffffffffffffffffff160361058a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f7665465853206d757374206e6f7420626520307830000000000000000000000060448201526064015b60405180910390fd5b5f61059b6040830160208401613cfe565b73ffffffffffffffffffffffffffffffffffffffff1603610618576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f76654658535574696c73206d757374206e6f74206265203078300000000000006044820152606401610581565b5f6106296060830160408401613cfe565b73ffffffffffffffffffffffffffffffffffffffff16036106a6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f43616e6e6f742061646420465049534c6f636b657220796574000000000000006044820152606401610581565b5f6106b76080830160608401613cfe565b73ffffffffffffffffffffffffffffffffffffffff1603610734576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f43616e6e6f742061646420465049534c6f636b65725574696c732079657400006044820152606401610581565b5f61074560a0830160808401613cfe565b73ffffffffffffffffffffffffffffffffffffffff16036107c2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f43616e6e6f7420616464204c31566546585320796574000000000000000000006044820152606401610581565b5f6107d360c0830160a08401613cfe565b73ffffffffffffffffffffffffffffffffffffffff1603610876576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f43616e6e6f7420616464204c315665465853546f74616c537570706c794f726160448201527f636c6520796574000000000000000000000000000000000000000000000000006064820152608401610581565b6108836020820182613cfe565b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff929092169190911790556108d86040820160208301613cfe565b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff929092169190911790555f61092e6060830160408401613cfe565b73ffffffffffffffffffffffffffffffffffffffff161415801561097757505f61095e6080830160608401613cfe565b73ffffffffffffffffffffffffffffffffffffffff1614155b15610a275761098c6060820160408301613cfe565b600480547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff929092169190911790556109e16080820160608301613cfe565b600780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff929092169190911790555b5f610a3860a0830160808401613cfe565b73ffffffffffffffffffffffffffffffffffffffff1614158015610a8157505f610a6860c0830160a08401613cfe565b73ffffffffffffffffffffffffffffffffffffffff1614155b15610b3157610a9660a0820160808301613cfe565b600580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055610aeb60c0820160a08301613cfe565b600880547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff929092169190911790555b50565b5f5473ffffffffffffffffffffffffffffffffffffffff163314801590610b73575060095473ffffffffffffffffffffffffffffffffffffffff163314155b15610baa576040517ffee4291a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8116610c27576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f5a65726f206164647265737320646574656374656400000000000000000000006044820152606401610581565b8073ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c70573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c94919061400b565b506040517f70a082310000000000000000000000000000000000000000000000000000000081525f600482015273ffffffffffffffffffffffffffffffffffffffff8216906370a0823190602401602060405180830381865afa158015610cfd573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d21919061400b565b506040517fb9ef08300000000000000000000000000000000000000000000000000000000081525f600482015273ffffffffffffffffffffffffffffffffffffffff82169063b9ef083090602401602060405180830381865afa158015610d8a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610dae9190614046565b508073ffffffffffffffffffffffffffffffffffffffff166366d6bff96040518163ffffffff1660e01b8152600401602060405180830381865afa158015610df8573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e1c919061406a565b6040517f3c5933120000000000000000000000000000000000000000000000000000000081525f600482015273ffffffffffffffffffffffffffffffffffffffff9190911690633c593312906024015f60405180830381865afa158015610e85573d5f803e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610eca91908101906141d5565b508073ffffffffffffffffffffffffffffffffffffffff166366d6bff96040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f14573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f38919061406a565b6040517f0c8d01e6000000000000000000000000000000000000000000000000000000008152670de0b6b3a7640000600482015262093a80602482015273ffffffffffffffffffffffffffffffffffffffff9190911690630c8d01e690604401602060405180830381865afa158015610fb3573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610fd7919061400b565b5073ffffffffffffffffffffffffffffffffffffffff81165f908152600b602052604090205460ff1615611067576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4164647265737320616c726561647920657869737473000000000000000000006044820152606401610581565b73ffffffffffffffffffffffffffffffffffffffff81165f818152600b6020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001908117909155600a805491820181559093527fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a890920180547fffffffffffffffffffffffff0000000000000000000000000000000000000000168417905590519182527f75ccbc951feec3500ed75b1652ef72542006274e6f34d220bc70e3342fce797e91015b60405180910390a150565b5f5473ffffffffffffffffffffffffffffffffffffffff163314611196576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce229060200161113b565b6060600a80548060200260200160405190810160405280929190818152602001828054801561126c57602002820191905f5260205f20905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311611241575b5050505050905090565b600a8181548110611285575f80fd5b5f9182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b600c5460ff16156112e8576040517fd08e7ac200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805473ffffffffffffffffffffffffffffffffffffffff8581167fffffffffffffffffffffffff000000000000000000000000000000000000000092831617909255600980548584169083161790558251600380548316918416919091179055602083015160068054909216908316179055604082015116158015906113885750606081015173ffffffffffffffffffffffffffffffffffffffff1615155b156113e95760408101516004805473ffffffffffffffffffffffffffffffffffffffff9283167fffffffffffffffffffffffff0000000000000000000000000000000000000000918216179091556060830151600780549190931691161790555b608081015173ffffffffffffffffffffffffffffffffffffffff161580159061142b575060a081015173ffffffffffffffffffffffffffffffffffffffff1615155b1561148c5760808101516005805473ffffffffffffffffffffffffffffffffffffffff9283167fffffffffffffffffffffffff00000000000000000000000000000000000000009182161790915560a0830151600880549190931691161790555b505050565b6114be6040518060a001604052805f81526020015f81526020015f81526020015f81526020015f81525090565b60035f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611528573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061154c919061400b565b808252608082015260045473ffffffffffffffffffffffffffffffffffffffff161561161d5760048054604080517f18160ddd000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff909216926318160ddd9282820192602092908290030181865afa1580156115dd573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611601919061400b565b602082018190526080820180516116199083906142f2565b9052505b60055473ffffffffffffffffffffffffffffffffffffffff161580159061165b575060085473ffffffffffffffffffffffffffffffffffffffff1615155b1561170a5760085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156116ca573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116ee919061400b565b604082018190526080820180516117069083906142f2565b9052505b5f5b600a548110156117fa575f600a828154811061172a5761172a613fde565b5f9182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905080156117f1575f8173ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561179d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117c1919061400b565b905080846060018181516117d591906142f2565b9052506080840180518291906117ec9083906142f2565b905250505b5060010161170c565b5090565b60015473ffffffffffffffffffffffffffffffffffffffff16331461184f576040517fd74b334e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f546001546040805173ffffffffffffffffffffffffffffffffffffffff93841681529290911660208301527fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c910160405180910390a1600180545f80547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff841617909155169055565b6003546040517fb9ef083000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301526060925f9291169063b9ef083090602401602060405180830381865afa158015611963573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119879190614046565b6004546fffffffffffffffffffffffffffffffff91909116915073ffffffffffffffffffffffffffffffffffffffff1615611a6f57600480546040517fb9ef083000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8781169382019390935291169063b9ef083090602401602060405180830381865afa158015611a2c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a509190614046565b611a6c906fffffffffffffffffffffffffffffffff16826142f2565b90505b60055473ffffffffffffffffffffffffffffffffffffffff1615801590611aad575060085473ffffffffffffffffffffffffffffffffffffffff1615155b15611ac057611abd6001826142f2565b90505b5f5b600a54811015611bbf575f600a8281548110611ae057611ae0613fde565b5f9182526020909120015473ffffffffffffffffffffffffffffffffffffffff1690508015611bb6576040517fb9ef083000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff878116600483015282169063b9ef083090602401602060405180830381865afa158015611b73573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b979190614046565b611bb3906fffffffffffffffffffffffffffffffff16846142f2565b92505b50600101611ac2565b505f808267ffffffffffffffff811115611bdb57611bdb613d8f565b604051908082528060200260200182016040528015611c5857816020015b6040805160c0810182525f8082526020808301829052928201819052606082018190526080820181905260a082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909201910181611bf95790505b506006546040517f3c59331200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff89811660048301529293505f9290911690633c593312906024015f60405180830381865afa158015611ccb573d5f803e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611d1091908101906141d5565b6060015190505f5b8151811015611ee0575f828281518110611d3457611d34613fde565b602002602001015190505f8815611e10576006546040830151606084015173ffffffffffffffffffffffffffffffffffffffff90921691630c8d01e69190611d7d90429061430b565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152600f9290920b60048301526fffffffffffffffffffffffffffffffff166024820152604401602060405180830381865afa158015611de9573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e0d919061400b565b90505b6040518060c00160405280835f0151815260200183602001516fffffffffffffffffffffffffffffffff1681526020018360400151600f0b815260200183606001516fffffffffffffffffffffffffffffffff16815260200160035f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815250858781518110611ebc57611ebc613fde565b602002602001018190525085611ed190614333565b95508260010192505050611d18565b505060045473ffffffffffffffffffffffffffffffffffffffff16156121a1576007546040517f3c59331200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff88811660048301525f921690633c593312906024015f60405180830381865afa158015611f6d573d5f803e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611fb291908101906141d5565b6060015190505f5b815181101561219e575f828281518110611fd657611fd6613fde565b602002602001015190504281606001516fffffffffffffffffffffffffffffffff161115612195575f88156120d0576007546040830151606084015173ffffffffffffffffffffffffffffffffffffffff90921691630e5f6d5d919061203d90429061430b565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152600f9290920b60048301526fffffffffffffffffffffffffffffffff166024820152604401602060405180830381865afa1580156120a9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120cd919061400b565b90505b6040518060c00160405280835f0151815260200183602001516fffffffffffffffffffffffffffffffff1681526020018360400151600f0b815260200183606001516fffffffffffffffffffffffffffffffff16815260200160045f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281525085878151811061217c5761217c613fde565b60200260200101819052508561219190614333565b9550505b50600101611fba565b50505b60055473ffffffffffffffffffffffffffffffffffffffff16158015906121df575060085473ffffffffffffffffffffffffffffffffffffffff1615155b156123b4576005546040517fcbf9fe5f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff88811660048301525f92169063cbf9fe5f90602401606060405180830381865afa158015612252573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906122769190614381565b905042816020015167ffffffffffffffff1611156123b2575f861561232a576005546040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a81166004830152909116906370a0823190602401602060405180830381865afa158015612303573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612327919061400b565b90505b6040805160c0810182525f8082526020808301919091528451600f0b928201929092529083015167ffffffffffffffff16606082015260055473ffffffffffffffffffffffffffffffffffffffff16608082015260a08101829052835184908690811061239957612399613fde565b6020026020010181905250836123ae90614333565b9350505b505b5f5b600a5481101561273b575f600a82815481106123d4576123d4613fde565b5f9182526020909120015473ffffffffffffffffffffffffffffffffffffffff1690508015612732575f8173ffffffffffffffffffffffffffffffffffffffff166366d6bff96040518163ffffffff1660e01b8152600401602060405180830381865afa158015612447573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061246b919061406a565b6040517f3c59331200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8b811660048301529190911690633c593312906024015f60405180830381865afa1580156124d6573d5f803e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261251b91908101906141d5565b6060015190505f5b815181101561272f575f82828151811061253f5761253f613fde565b602002602001015190505f8a15612680578473ffffffffffffffffffffffffffffffffffffffff166366d6bff96040518163ffffffff1660e01b8152600401602060405180830381865afa158015612599573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906125bd919061406a565b73ffffffffffffffffffffffffffffffffffffffff16630c8d01e683604001514285606001516125ed919061430b565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152600f9290920b60048301526fffffffffffffffffffffffffffffffff166024820152604401602060405180830381865afa158015612659573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061267d919061400b565b90505b6040518060c00160405280835f0151815260200183602001516fffffffffffffffffffffffffffffffff1681526020018360400151600f0b815260200183606001516fffffffffffffffffffffffffffffffff1681526020018673ffffffffffffffffffffffffffffffffffffffff1681526020018281525087898151811061270b5761270b613fde565b60200260200101819052508761272090614333565b97508260010192505050612523565b50505b506001016123b6565b508167ffffffffffffffff81111561275557612755613d8f565b6040519080825280602002602001820160405280156127d257816020015b6040805160c0810182525f8082526020808301829052928201819052606082018190526080820181905260a082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816127735790505b5093505f5b845181101561281f578181815181106127f2576127f2613fde565b602002602001015185828151811061280c5761280c613fde565b60209081029190910101526001016127d7565b5050505092915050565b5f5473ffffffffffffffffffffffffffffffffffffffff163314801590612868575060095473ffffffffffffffffffffffffffffffffffffffff163314155b1561289f576040517ffee4291a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f546128c390839073ffffffffffffffffffffffffffffffffffffffff1683613b7e565b6040805173ffffffffffffffffffffffffffffffffffffffff84168152602081018390527f55350610fe57096d8c0ffa30beede987326bccfcb0b4415804164d0dd50ce8b1910160405180910390a15050565b6003546040517fb9ef083000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301526060925f9291169063b9ef083090602401602060405180830381865afa158015612988573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906129ac9190614046565b6004546fffffffffffffffffffffffffffffffff91909116915073ffffffffffffffffffffffffffffffffffffffff1615612a9457600480546040517fb9ef083000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8681169382019390935291169063b9ef083090602401602060405180830381865afa158015612a51573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612a759190614046565b612a91906fffffffffffffffffffffffffffffffff16826142f2565b90505b60055473ffffffffffffffffffffffffffffffffffffffff1615801590612ad2575060085473ffffffffffffffffffffffffffffffffffffffff1615155b15612ae557612ae26001826142f2565b90505b5f5b600a54811015612be4575f600a8281548110612b0557612b05613fde565b5f9182526020909120015473ffffffffffffffffffffffffffffffffffffffff1690508015612bdb576040517fb9ef083000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff868116600483015282169063b9ef083090602401602060405180830381865afa158015612b98573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612bbc9190614046565b612bd8906fffffffffffffffffffffffffffffffff16846142f2565b92505b50600101612ae7565b505f808267ffffffffffffffff811115612c0057612c00613d8f565b604051908082528060200260200182016040528015612c7d57816020015b6040805160c0810182525f8082526020808301829052928201819052606082018190526080820181905260a082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909201910181612c1e5790505b506006546040517f3c59331200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff88811660048301529293505f9290911690633c593312906024015f60405180830381865afa158015612cf0573d5f803e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612d3591908101906141d5565b6080015190505f5b8151811015612e2f575f828281518110612d5957612d59613fde565b602002602001015190506040518060c00160405280825f0151815260200182602001516fffffffffffffffffffffffffffffffff1681526020018260400151600f0b815260200182606001516fffffffffffffffffffffffffffffffff16815260200160035f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020015f815250848681518110612e0f57612e0f613fde565b602002602001018190525084612e2490614333565b945050600101612d3d565b505060045473ffffffffffffffffffffffffffffffffffffffff1615612ffe576007546040517f3c59331200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87811660048301525f921690633c593312906024015f60405180830381865afa158015612ebc573d5f803e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612f0191908101906141d5565b6080015190505f5b8151811015612ffb575f828281518110612f2557612f25613fde565b602002602001015190506040518060c00160405280825f0151815260200182602001516fffffffffffffffffffffffffffffffff1681526020018260400151600f0b815260200182606001516fffffffffffffffffffffffffffffffff16815260200160045f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020015f815250848681518110612fdb57612fdb613fde565b602002602001018190525084612ff090614333565b945050600101612f09565b50505b60055473ffffffffffffffffffffffffffffffffffffffff161580159061303c575060085473ffffffffffffffffffffffffffffffffffffffff1615155b15613173576005546040517fcbf9fe5f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87811660048301525f92169063cbf9fe5f90602401606060405180830381865afa1580156130af573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906130d39190614381565b905042816020015167ffffffffffffffff1611613171576040805160c0810182525f80825260208083018290528451600f0b938301939093529183015167ffffffffffffffff16606082015260055473ffffffffffffffffffffffffffffffffffffffff16608082015260a0810191909152825183908590811061315957613159613fde565b60200260200101819052508261316e90614333565b92505b505b5f5b600a548110156133bf575f600a828154811061319357613193613fde565b5f9182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905080156133b6575f8173ffffffffffffffffffffffffffffffffffffffff166366d6bff96040518163ffffffff1660e01b8152600401602060405180830381865afa158015613206573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061322a919061406a565b6040517f3c59331200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a811660048301529190911690633c593312906024015f60405180830381865afa158015613295573d5f803e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526132da91908101906141d5565b6080015190505f5b81518110156133b3575f8282815181106132fe576132fe613fde565b602002602001015190506040518060c00160405280825f0151815260200182602001516fffffffffffffffffffffffffffffffff1681526020018260400151600f0b815260200182606001516fffffffffffffffffffffffffffffffff1681526020018573ffffffffffffffffffffffffffffffffffffffff1681526020015f81525086888151811061339357613393613fde565b6020026020010181905250866133a890614333565b9650506001016132e2565b50505b50600101613175565b508167ffffffffffffffff8111156133d9576133d9613d8f565b60405190808252806020026020018201604052801561345657816020015b6040805160c0810182525f8082526020808301829052928201819052606082018190526080820181905260a082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816133f75790505b5093505f5b84518110156134a35781818151811061347657613476613fde565b602002602001015185828151811061349057613490613fde565b602090810291909101015260010161345b565b50505050919050565b5f5473ffffffffffffffffffffffffffffffffffffffff1633148015906134eb575060095473ffffffffffffffffffffffffffffffffffffffff163314155b15613522576040517ffee4291a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600980547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6003546040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301525f9216906370a0823190602401602060405180830381865afa1580156135d7573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906135fb919061400b565b60045490915073ffffffffffffffffffffffffffffffffffffffff16156136bd57600480546040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff858116938201939093529116906370a0823190602401602060405180830381865afa15801561368c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906136b0919061400b565b6136ba90826142f2565b90505b60055473ffffffffffffffffffffffffffffffffffffffff16158015906136fb575060085473ffffffffffffffffffffffffffffffffffffffff1615155b1561379f576005546040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152909116906370a0823190602401602060405180830381865afa15801561376e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613792919061400b565b61379c90826142f2565b90505b5f5b600a5481101561388c575f600a82815481106137bf576137bf613fde565b5f9182526020909120015473ffffffffffffffffffffffffffffffffffffffff1690508015613883576040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301528216906370a0823190602401602060405180830381865afa158015613852573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613876919061400b565b61388090846142f2565b92505b506001016137a1565b50919050565b5f8061389c611491565b6080015192915050565b5f5473ffffffffffffffffffffffffffffffffffffffff1633148015906138e5575060095473ffffffffffffffffffffffffffffffffffffffff163314155b1561391c576040517ffee4291a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8116613999576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f5a65726f206164647265737320646574656374656400000000000000000000006044820152606401610581565b73ffffffffffffffffffffffffffffffffffffffff81165f908152600b602052604090205460ff161515600114613a2c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f41646472657373206e6f6e6578697374656e74000000000000000000000000006044820152606401610581565b73ffffffffffffffffffffffffffffffffffffffff81165f908152600b6020526040812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555b600a54811015613b37578173ffffffffffffffffffffffffffffffffffffffff16600a8281548110613aab57613aab613fde565b5f9182526020909120015473ffffffffffffffffffffffffffffffffffffffff1603613b2f575f600a8281548110613ae557613ae5613fde565b905f5260205f20015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550613b37565b600101613a77565b5060405173ffffffffffffffffffffffffffffffffffffffff821681527ff3517f912cde760e82811897047177df419c7aa16326d5710e6b425a8a7d10359060200161113b565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905291515f92839290871691613c1491906143ed565b5f604051808303815f865af19150503d805f8114613c4d576040519150601f19603f3d011682016040523d82523d5f602084013e613c52565b606091505b5091509150811580613c805750805115801590613c80575080806020019051810190613c7e9190614403565b155b15613cb7576040517f19a9708500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b5f60c08284031215613cce575f80fd5b8260c08301111561388c575f80fd5b73ffffffffffffffffffffffffffffffffffffffff81168114610b31575f80fd5b5f60208284031215613d0e575f80fd5b8135613d1981613cdd565b9392505050565b602080825282518282018190525f918401906040840190835b81811015613d6d57835173ffffffffffffffffffffffffffffffffffffffff16835260209384019390920191600101613d39565b509095945050505050565b5f60208284031215613d88575f80fd5b5035919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b60405160c0810167ffffffffffffffff81118282101715613ddf57613ddf613d8f565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613e2c57613e2c613d8f565b604052919050565b5f805f6101008486031215613e47575f80fd5b8335613e5281613cdd565b92506020840135613e6281613cdd565b9150605f84018513613e72575f80fd5b613e7c60c0613de5565b80610100860187811115613e8e575f80fd5b604087015b81811015613eb4578035613ea681613cdd565b845260209384019301613e93565b505080925050509250925092565b8015158114610b31575f80fd5b5f8060408385031215613ee0575f80fd5b8235613eeb81613cdd565b91506020830135613efb81613ec2565b809150509250929050565b602080825282518282018190525f918401906040840190835b81811015613d6d578351805184526fffffffffffffffffffffffffffffffff60208201511660208501526040810151600f0b60408501526fffffffffffffffffffffffffffffffff606082015116606085015273ffffffffffffffffffffffffffffffffffffffff608082015116608085015260a081015160a08501525060c083019250602084019350600181019050613f1f565b5f8060408385031215613fc5575f80fd5b8235613fd081613cdd565b946020939093013593505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f6020828403121561401b575f80fd5b5051919050565b80516fffffffffffffffffffffffffffffffff81168114614041575f80fd5b919050565b5f60208284031215614056575f80fd5b613d1982614022565b805161404181613cdd565b5f6020828403121561407a575f80fd5b8151613d1981613cdd565b8051600f81900b8114614041575f80fd5b5f82601f8301126140a5575f80fd5b8151602083015f8067ffffffffffffffff8411156140c5576140c5613d8f565b60208460051b0190506140d781613de5565b84815260079490941b83019391505060208101868411156140f6575f80fd5b83831015614180575f6080848903121561410e575f80fd5b6040516080810167ffffffffffffffff8111828210171561413157614131613d8f565b6040528451808252915061414760208601614022565b602082015261415860408601614085565b604082015261416960608601614022565b6060820152825250608092909201916020016140f6565b5095945050505050565b5f82601f830112614199575f80fd5b6141a36060613de5565b8060608401858111156141b4575f80fd5b845b81811015613d6d576141c781614085565b8452602093840193016141b6565b5f602082840312156141e5575f80fd5b815167ffffffffffffffff8111156141fb575f80fd5b8201610100818503121561420d575f80fd5b614215613dbc565b61421e8261405f565b815260208281015190820152604082015167ffffffffffffffff811115614243575f80fd5b61424f86828501614096565b604083015250606082015167ffffffffffffffff81111561426e575f80fd5b61427a86828501614096565b606083015250608082015167ffffffffffffffff811115614299575f80fd5b6142a586828501614096565b6080830152506142b88560a0840161418a565b60a0820152949350505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115614305576143056142c5565b92915050565b6fffffffffffffffffffffffffffffffff8281168282160390811115614305576143056142c5565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614363576143636142c5565b5060010190565b805167ffffffffffffffff81168114614041575f80fd5b5f6060828403128015614392575f80fd5b506040516060810167ffffffffffffffff811182821017156143b6576143b6613d8f565b6040526143c283614022565b81526143d06020840161436a565b60208201526143e16040840161436a565b60408201529392505050565b5f82518060208501845e5f920191825250919050565b5f60208284031215614413575f80fd5b8151613d1981613ec256fea2646970667358221220906e77c6f61b3057feae5009f729232e2975ab0fb6ae39d9a4d084df7d210dc164736f6c634300081a0033

Deployed Bytecode Sourcemap

156667:31874:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;185171:1298;;;;;;:::i;:::-;;:::i;:::-;;182718:784;;;;;;:::i;:::-;;:::i;157588:56::-;;;;;;;;;;;;892:42:1;880:55;;;862:74;;850:2;835:18;157588:56:0;;;;;;;;101035:141;;;;;;:::i;:::-;;:::i;157085:23::-;;;;;;;;;157978:47;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;1363:14:1;;1356:22;1338:41;;1326:2;1311:18;157978:47:0;1198:187:1;157746:30:0;;;;;;;;;165354:134;;;:::i;:::-;;;;;;;:::i;100886:29::-;;;;;;;;;157852:35;;;;;;:::i;:::-;;:::i;160111:1089::-;;;;;;:::i;:::-;;:::i;162867:1836::-;;;:::i;:::-;;;;;;4509:4:1;4551:3;4540:9;4536:19;4528:27;;4588:6;4582:13;4571:9;4564:32;4652:4;4644:6;4640:17;4634:24;4627:4;4616:9;4612:20;4605:54;4715:4;4707:6;4703:17;4697:24;4690:4;4679:9;4675:20;4668:54;4778:4;4770:6;4766:17;4760:24;4753:4;4742:9;4738:20;4731:54;4841:4;4833:6;4829:17;4823:24;4816:4;4805:9;4801:20;4794:54;4333:521;;;;;157159:29:0;;;;;;;;;101184:354;;;:::i;166037:8890::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;184644:306::-;;;;;;:::i;:::-;;:::i;100859:20::-;;;;;;;;;175270:6914;;;;;;:::i;:::-;;:::i;186576:114::-;;;;;;:::i;:::-;;:::i;165603:127::-;165697:18;:25;165603:127;;;7294:25:1;;;7282:2;7267:18;165603:127:0;7148:177:1;161606:1006:0;;;;;;:::i;:::-;;:::i;157276:23::-;;;;;;;;;165016:231;;;:::i;183708:698::-;;;;;;:::i;:::-;;:::i;157363:33::-;;;;;;;;;157471;;;;;;;;;185171:1298;159411:5;;;;159397:10;:19;;;;:52;;-1:-1:-1;159434:15:0;;;;159420:10;:29;;159397:52;159393:85;;;159458:20;;;;;;;;;;;;;;159393:85;185373:1:::1;185346:15;;::::0;::::1;:12:::0;:15:::1;:::i;:::-;:29;;::::0;185338:63:::1;;;::::0;::::1;::::0;;8481:2:1;185338:63:0::1;::::0;::::1;8463:21:1::0;8520:2;8500:18;;;8493:30;8559:23;8539:18;;;8532:51;8600:18;;185338:63:0::1;;;;;;;;;185447:1;185420:15;::::0;;;::::1;::::0;::::1;;:::i;:::-;:29;;::::0;185412:68:::1;;;::::0;::::1;::::0;;8831:2:1;185412:68:0::1;::::0;::::1;8813:21:1::0;8870:2;8850:18;;;8843:30;8909:28;8889:18;;;8882:56;8955:18;;185412:68:0::1;8629:350:1::0;185412:68:0::1;185526:1;185499:15;::::0;;;;;::::1;;:::i;:::-;:29;;::::0;185491:67:::1;;;::::0;::::1;::::0;;9186:2:1;185491:67:0::1;::::0;::::1;9168:21:1::0;9225:2;9205:18;;;9198:30;9264:27;9244:18;;;9237:55;9309:18;;185491:67:0::1;8984:349:1::0;185491:67:0::1;185604:1;185577:15;::::0;;;;;::::1;;:::i;:::-;:29;;::::0;185569:72:::1;;;::::0;::::1;::::0;;9540:2:1;185569:72:0::1;::::0;::::1;9522:21:1::0;9579:2;9559:18;;;9552:30;9618:32;9598:18;;;9591:60;9668:18;;185569:72:0::1;9338:354:1::0;185569:72:0::1;185687:1;185660:15;::::0;;;;;::::1;;:::i;:::-;:29;;::::0;185652:64:::1;;;::::0;::::1;::::0;;9899:2:1;185652:64:0::1;::::0;::::1;9881:21:1::0;9938:2;9918:18;;;9911:30;9977:24;9957:18;;;9950:52;10019:18;;185652:64:0::1;9697:346:1::0;185652:64:0::1;185762:1;185735:15;::::0;;;;;::::1;;:::i;:::-;:29;;::::0;185727:81:::1;;;::::0;::::1;::::0;;10250:2:1;185727:81:0::1;::::0;::::1;10232:21:1::0;10289:2;10269:18;;;10262:30;10328:34;10308:18;;;10301:62;10399:9;10379:18;;;10372:37;10426:19;;185727:81:0::1;10048:403:1::0;185727:81:0::1;185877:15;;::::0;::::1;:12:::0;:15:::1;:::i;:::-;185858:5;:35:::0;;;::::1;;::::0;;;::::1;::::0;;;::::1;::::0;;185933:15:::1;::::0;;;::::1;::::0;::::1;;:::i;:::-;185904:10;:45:::0;;;::::1;;::::0;;;::::1;::::0;;;::::1;::::0;;-1:-1:-1;185991:15:0::1;::::0;;;;;::::1;;:::i;:::-;:29;;;;185990:64;;;;-1:-1:-1::0;186052:1:0::1;186025:15;::::0;;;;;::::1;;:::i;:::-;:29;;;;185990:64;185986:198;;;186096:15;::::0;;;;;::::1;;:::i;:::-;186071:10;:41:::0;;;::::1;;::::0;;;::::1;::::0;;;::::1;::::0;;186156:15:::1;::::0;;;;;::::1;;:::i;:::-;186127:10;:45:::0;;;::::1;;::::0;;;::::1;::::0;;;::::1;::::0;;185986:198:::1;186277:1;186250:15;::::0;;;;;::::1;;:::i;:::-;:29;;;;186249:66;;;;-1:-1:-1::0;186312:1:0::1;186285:15;::::0;;;;;::::1;;:::i;:::-;:29;;;;186249:66;186245:217;;;186351:15;::::0;;;;;::::1;;:::i;:::-;186332:7;:35:::0;;;::::1;;::::0;;;::::1;::::0;;;::::1;::::0;;186434:15:::1;::::0;;;;;::::1;;:::i;:::-;186382:24;:68:::0;;;::::1;;::::0;;;::::1;::::0;;;::::1;::::0;;186245:217:::1;185171:1298:::0;:::o;182718:784::-;159411:5;;;;159397:10;:19;;;;:52;;-1:-1:-1;159434:15:0;;;;159420:10;:29;;159397:52;159393:85;;;159458:20;;;;;;;;;;;;;;159393:85;182802:19:::1;::::0;::::1;182794:53;;;::::0;::::1;::::0;;10658:2:1;182794:53:0::1;::::0;::::1;10640:21:1::0;10697:2;10677:18;;;10670:30;10736:23;10716:18;;;10709:51;10777:18;;182794:53:0::1;10456:345:1::0;182794:53:0::1;182972:5;182961:29;;;:31;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;183003:39:0::1;::::0;;;;183039:1:::1;183003:39;::::0;::::1;862:74:1::0;183003:27:0::1;::::0;::::1;::::0;::::1;::::0;835:18:1;;183003:39:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;183053:38:0::1;::::0;;;;183088:1:::1;183053:38;::::0;::::1;862:74:1::0;183053:26:0::1;::::0;::::1;::::0;::::1;::::0;835:18:1;;183053:38:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;183129:5;183118:28;;;:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;183102:83;::::0;;;;183182:1:::1;183102:83;::::0;::::1;862:74:1::0;183102:71:0::1;::::0;;;::::1;::::0;::::1;::::0;835:18:1;;183102:83:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;::::0;;::::1;::::0;::::1;::::0;::::1;;::::0;::::1;::::0;;;::::1;::::0;::::1;:::i;:::-;;183223:5;183212:28;;;:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;183196:91;::::0;;;;183273:4:::1;183196:91;::::0;::::1;15743:41:1::0;183279:7:0::1;15800:18:1::0;;;15793:75;183196:76:0::1;::::0;;;::::1;::::0;::::1;::::0;15716:18:1;;183196:91:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;183308:22:0::1;::::0;::::1;;::::0;;;:15:::1;:22;::::0;;;;;::::1;;:31;183300:66;;;::::0;::::1;::::0;;16081:2:1;183300:66:0::1;::::0;::::1;16063:21:1::0;16120:2;16100:18;;;16093:30;16159:24;16139:18;;;16132:52;16201:18;;183300:66:0::1;15879:346:1::0;183300:66:0::1;183377:22;::::0;::::1;;::::0;;;:15:::1;:22;::::0;;;;;;;:29;;;::::1;183402:4;183377:29:::0;;::::1;::::0;;;183417:18:::1;:30:::0;;;;::::1;::::0;;;;;;;;::::1;::::0;;;::::1;::::0;::::1;::::0;;183465:29;;862:74:1;;;183465:29:0::1;::::0;835:18:1;183465:29:0::1;;;;;;;;182718:784:::0;:::o;101035:141::-;101689:5;;;;101675:10;:19;101671:43;;101703:11;;;;;;;;;;;;;;101671:43;101107:14:::1;:23:::0;;;::::1;;::::0;::::1;::::0;;::::1;::::0;;;101146:22:::1;::::0;862:74:1;;;101146:22:0::1;::::0;850:2:1;835:18;101146:22:0::1;683:259:1::0;165354:134:0;165415:27;165462:18;165455:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;165354:134;:::o;157852:35::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;157852:35:0;:::o;160111:1089::-;160320:14;;;;160316:45;;;160343:18;;;;;;;;;;;;;;160316:45;160408:5;:14;;;;;;;;;;;;;;160466:15;:34;;;;;;;;;;;160570:15;;160551:5;:35;;;;;;;;;;;;;160570:15;160626;;;-1:-1:-1;160597:45:0;;;;;;;;;;;160702:15;;;;:29;;;;;160701:66;;-1:-1:-1;160737:15:0;;;;:29;;;;160701:66;160697:200;;;160809:15;;;;160784:10;:41;;;;;;;;;;;;;;160869:15;;;;160840:10;:45;;;;;;;;;;;160697:200;160981:15;;;;:29;;;;;;160980:66;;-1:-1:-1;161016:15:0;;;;:29;;;;160980:66;160976:217;;;161082:15;;;;161063:7;:35;;;;;;;;;;;;;;161165:15;;;;161113:24;:68;;;;;;;;;;;160976:217;160111:1089;;;:::o;162867:1836::-;162935:42;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;162935:42:0;163135:5;;;;;;;;;;;:17;;;:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;163106:48;;;163165:22;;;:51;163374:10;;163366:33;163374:10;163366:33;163362:285;;163446:10;;;:24;;;;;;;;:10;;;;;:22;;:24;;;;;;;;;;;;:10;:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;163416:27;;;:54;;;163485:22;;;:53;;;;163416:54;;163485:53;:::i;:::-;;;-1:-1:-1;163362:285:0;163757:7;;163749:30;163757:7;163749:30;;;;163748:85;;-1:-1:-1;163793:24:0;;163785:47;163793:24;163785:47;;163748:85;163744:356;;;163877:24;;;;;;;;;;;:36;;;:38;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;163850:24;;;:65;;;163930:22;;;:50;;;;163850:65;;163930:50;:::i;:::-;;;-1:-1:-1;163744:356:0;164172:9;164167:529;164187:18;:25;164183:29;;164167:529;;;164231:15;164249:18;164268:1;164249:21;;;;;;;;:::i;:::-;;;;;;;;;;;;;;-1:-1:-1;164289:21:0;;164285:336;;164331:19;164364:7;164353:31;;;:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;164331:55;;164438:11;164405;:29;;:44;;;;;;;:::i;:::-;;;-1:-1:-1;164468:22:0;;;:37;;164494:11;;164468:22;:37;;164494:11;;164468:37;:::i;:::-;;;-1:-1:-1;;164285:336:0;-1:-1:-1;164666:3:0;;164167:529;;;;162867:1836;:::o;101184:354::-;101357:14;;;;101343:10;:28;101339:69;;101380:28;;;;;;;;;;;;;;101339:69;101437:5;;;101444:14;101424:35;;;101437:5;;;;16723:74:1;;101444:14:0;;;;16828:2:1;16813:18;;16806:83;101424:35:0;;16696:18:1;101424:35:0;;;;;;;101478:14;;;;101470:22;;;;;;101478:14;;;101470:22;;;;101503:27;;;101184:354::o;166037:8890::-;166442:5;;:24;;;;;:5;880:55:1;;;166442:24:0;;;862:74:1;166158:49:0;;166420:19;;166442:5;;;:14;;835:18:1;;166442:24:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;166526:10;;166420:46;;;;;;-1:-1:-1;166518:33:0;166526:10;166518:33;166514:83;;166568:10;;;:29;;;;;:10;880:55:1;;;166568:29:0;;;862:74:1;;;;166568:10:0;;;:19;;835:18:1;;166568:29:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;166553:44;;;;;;:::i;:::-;;;166514:83;166654:7;;166646:30;166654:7;166646:30;;;;166645:85;;-1:-1:-1;166690:24:0;;166682:47;166690:24;166682:47;;166645:85;166641:179;;;166747:16;166762:1;166747:16;;:::i;:::-;;;166641:179;166924:9;166919:301;166943:18;:25;166939:29;;166919:301;;;166990:15;167008:18;167027:1;167008:21;;;;;;;;:::i;:::-;;;;;;;;;;;;;;-1:-1:-1;167048:21:0;;167044:165;;167155:38;;;;;:28;880:55:1;;;167155:38:0;;;862:74:1;167155:28:0;;;;;835:18:1;;167155:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;167140:53;;;;;;:::i;:::-;;;167044:165;-1:-1:-1;166970:3:0;;166919:301;;;;167279:22;167316:48;167397:11;167367:42;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;167367:42:0;;;;;;;;;;;;;;-1:-1:-1;167655:10:0;;:44;;;;;:10;880:55:1;;;167655:44:0;;;862:74:1;167316:93:0;;-1:-1:-1;167596:55:0;;167655:10;;;;:34;;835:18:1;;167655:44:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;167654:76;;;167596:134;;167839:9;167834:1288;167854:24;:31;167850:1;:35;167834:1288;;;167956:61;168020:24;168045:1;168020:27;;;;;;;;:::i;:::-;;;;;;;167956:91;;168167:23;168213:19;168209:276;;;168275:10;;168341:25;;;;168393:22;;;;168275:10;;;;;:39;;168341:25;168393:49;;168426:15;;168393:49;:::i;:::-;168275:190;;;;;;;;;;15772:2:1;15761:22;;;;168275:190:0;;;15743:41:1;15832:34;15820:47;15800:18;;;15793:75;15716:18;;168275:190:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;168257:208;;168209:276;168581:361;;;;;;;;168632:18;:21;;;168581:361;;;;168683:18;:24;;;168581:361;;;;;;168738:18;:25;;;168581:361;;;;;;168791:18;:22;;;168581:361;;;;;;168854:5;;;;;;;;;;;168581:361;;;;;;168907:15;168581:361;;;168547:15;168563:14;168547:31;;;;;;;;:::i;:::-;;;;;;:395;;;;169014:16;;;;:::i;:::-;;;169084:3;;;;;167889:1233;;167834:1288;;;-1:-1:-1;;169230:10:0;;169222:33;169230:10;169222:33;169218:1852;;169411:10;;:44;;;;;:10;880:55:1;;;169411:44:0;;;862:74:1;169319:70:0;;169411:10;;:34;;835:18:1;;169411:44:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;169392:90;;;169319:163;;169589:9;169584:1475;169604:25;:32;169600:1;:36;169584:1475;;;169707:56;169766:25;169792:1;169766:28;;;;;;;;:::i;:::-;;;;;;;169707:87;;169881:15;169861:13;:17;;;:35;;;169857:1111;;;170024:23;170074:19;170070:286;;;170140:10;;170210:20;;;;170261:17;;;;170140:10;;;;;:39;;170210:20;170261:44;;170289:15;;170261:44;:::i;:::-;170140:192;;;;;;;;;;15772:2:1;15761:22;;;;170140:192:0;;;15743:41:1;15832:34;15820:47;15800:18;;;15793:75;15716:18;;170140:192:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;170122:210;;170070:286;170478:374;;;;;;;;170533:13;:16;;;170478:374;;;;170583:13;:19;;;170478:374;;;;;;170637:13;:20;;;170478:374;;;;;;170689:13;:17;;;170478:374;;;;;;170751:10;;;;;;;;;;;170478:374;;;;;;170813:15;170478:374;;;170444:15;170460:14;170444:31;;;;;;;;:::i;:::-;;;;;;:408;;;;170932:16;;;;:::i;:::-;;;169898:1070;169857:1111;-1:-1:-1;171021:3:0;;169584:1475;;;;169257:1813;169218:1852;171164:7;;171156:30;171164:7;171156:30;;;;171155:85;;-1:-1:-1;171200:24:0;;171192:47;171200:24;171192:47;;171155:85;171151:1221;;;171344:7;;:24;;;;;:7;880:55:1;;;171344:24:0;;;862:74:1;171295:46:0;;171344:7;;:14;;835:18:1;;171344:24:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;171295:73;;171547:15;171524:16;:20;;;:38;;;171520:841;;;171682:23;171728:19;171724:113;;;171790:7;;:27;;;;;:7;880:55:1;;;171790:27:0;;;862:74:1;171790:7:0;;;;:17;;835:18:1;;171790:27:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;171772:45;;171724:113;171933:324;;;;;;;;-1:-1:-1;171933:324:0;;;;;;;;;;;172054:23;;171933:324;;;;;;;;;172106:20;;;;171933:324;;;;;;172167:7;;;;171933:324;;;;;;;;;;171899:31;;:15;;171915:14;;171899:31;;;;;;:::i;:::-;;;;;;:358;;;;172329:16;;;;:::i;:::-;;;171564:797;171520:841;171242:1130;171151:1221;172494:9;172489:2055;172509:18;:25;172505:29;;172489:2055;;;172553:15;172571:18;172590:1;172571:21;;;;;;;;:::i;:::-;;;;;;;;;;;;;;-1:-1:-1;172611:21:0;;172607:1862;;172694:55;172802:7;172791:30;;;:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;172775:83;;;;;:73;880:55:1;;;172775:83:0;;;862:74:1;172775:73:0;;;;;;;835:18:1;;172775:83:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;172752:137;;;172694:195;;172999:9;172994:1460;173014:24;:31;173010:1;:35;172994:1460;;;173124:60;173187:24;173212:1;173187:27;;;;;;;;:::i;:::-;;;;;;;173124:90;;173342:23;173392:19;173388:375;;;173485:7;173474:30;;;:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;173458:108;;;173601:17;:24;;;173692:15;173660:17;:21;;;:48;;;;:::i;:::-;173458:281;;;;;;;;;;15772:2:1;15761:22;;;;173458:281:0;;;15743:41:1;15832:34;15820:47;15800:18;;;15793:75;15716:18;;173458:281:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;173440:299;;173388:375;173872:378;;;;;;;;173927:17;:20;;;173872:378;;;;173981:17;:23;;;173872:378;;;;;;174039:17;:24;;;173872:378;;;;;;174095:17;:21;;;173872:378;;;;;;174153:7;173872:378;;;;;;174211:15;173872:378;;;173838:15;173854:14;173838:31;;;;;;;;:::i;:::-;;;;;;:412;;;;174330:16;;;;:::i;:::-;;;174408:3;;;;;173049:1405;;172994:1460;;;;172634:1835;172607:1862;-1:-1:-1;174514:3:0;;172489:2055;;;;174680:14;174650:45;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;174650:45:0;;;;;;;;;;;;;;;174631:64;;174747:9;174742:178;174762:16;:23;174758:1;:27;174742:178;;;174826:15;174842:1;174826:18;;;;;;;;:::i;:::-;;;;;;;174804:16;174821:1;174804:19;;;;;;;;:::i;:::-;;;;;;;;;;:40;174890:3;;174742:178;;;;166209:8718;;;166037:8890;;;;:::o;184644:306::-;159411:5;;;;159397:10;:19;;;;:52;;-1:-1:-1;159434:15:0;;;;159420:10;:29;;159397:52;159393:85;;;159458:20;;;;;;;;;;;;;;159393:85;184863:5:::1;::::0;184820:63:::1;::::0;184848:13;;184863:5:::1;;184870:12:::0;184820:27:::1;:63::i;:::-;184899:43;::::0;;20123:42:1;20111:55;;20093:74;;20198:2;20183:18;;20176:34;;;184899:43:0::1;::::0;20066:18:1;184899:43:0::1;;;;;;;184644:306:::0;;:::o;175270:6914::-;175619:5;;:24;;;;;:5;880:55:1;;;175619:24:0;;;862:74:1;175337:46:0;;175597:19;;175619:5;;;:14;;835:18:1;;175619:24:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;175703:10;;175597:46;;;;;;-1:-1:-1;175695:33:0;175703:10;175695:33;175691:83;;175745:10;;;:29;;;;;:10;880:55:1;;;175745:29:0;;;862:74:1;;;;175745:10:0;;;:19;;835:18:1;;175745:29:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;175730:44;;;;;;:::i;:::-;;;175691:83;175831:7;;175823:30;175831:7;175823:30;;;;175822:85;;-1:-1:-1;175867:24:0;;175859:47;175867:24;175859:47;;175822:85;175818:179;;;175924:16;175939:1;175924:16;;:::i;:::-;;;175818:179;176101:9;176096:301;176120:18;:25;176116:29;;176096:301;;;176167:15;176185:18;176204:1;176185:21;;;;;;;;:::i;:::-;;;;;;;;;;;;;;-1:-1:-1;176225:21:0;;176221:165;;176332:38;;;;;:28;880:55:1;;;176332:38:0;;;862:74:1;176332:28:0;;;;;835:18:1;;176332:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;176317:53;;;;;;:::i;:::-;;;176221:165;-1:-1:-1;176147:3:0;;176096:301;;;;176456:23;176494:49;176576:11;176546:42;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;176546:42:0;;;;;;;;;;;;;;-1:-1:-1;176834:10:0;;:44;;;;;:10;880:55:1;;;176834:44:0;;;862:74:1;176494:94:0;;-1:-1:-1;176775:55:0;;176834:10;;;;:34;;835:18:1;;176834:44:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;176833:77;;;176775:135;;177019:9;177014:841;177034:24;:31;177030:1;:35;177014:841;;;177136:61;177200:24;177225:1;177200:27;;;;;;;;:::i;:::-;;;;;;;177136:91;;177326:347;;;;;;;;177377:18;:21;;;177326:347;;;;177428:18;:24;;;177326:347;;;;;;177483:18;:25;;;177326:347;;;;;;177536:18;:22;;;177326:347;;;;;;177599:5;;;;;;;;;;;177326:347;;;;;;177652:1;177326:347;;;177290:16;177307:15;177290:33;;;;;;;;:::i;:::-;;;;;;:383;;;;177746:17;;;;:::i;:::-;;-1:-1:-1;;177817:3:0;;177014:841;;;-1:-1:-1;;177963:10:0;;177955:33;177963:10;177955:33;177951:1219;;178144:10;;:44;;;;;:10;880:55:1;;;178144:44:0;;;862:74:1;178052:70:0;;178144:10;;:34;;835:18:1;;178144:44:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;178125:91;;;178052:164;;178323:9;178318:841;178338:25;:32;178334:1;:36;178318:841;;;178441:56;178500:25;178526:1;178500:28;;;;;;;;:::i;:::-;;;;;;;178441:87;;178645:332;;;;;;;;178696:13;:16;;;178645:332;;;;178742:13;:19;;;178645:332;;;;;;178792:13;:20;;;178645:332;;;;;;178840:13;:17;;;178645:332;;;;;;178898:10;;;;;;;;;;;178645:332;;;;;;178956:1;178645:332;;;178609:16;178626:15;178609:33;;;;;;;;:::i;:::-;;;;;;:368;;;;179050:17;;;;:::i;:::-;;-1:-1:-1;;179121:3:0;;178318:841;;;;177990:1180;177951:1219;179264:7;;179256:30;179264:7;179256:30;;;;179255:85;;-1:-1:-1;179300:24:0;;179292:47;179300:24;179292:47;;179255:85;179251:939;;;179444:7;;:24;;;;;:7;880:55:1;;;179444:24:0;;;862:74:1;179395:46:0;;179444:7;;:14;;835:18:1;;179444:24:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;179395:73;;179649:15;179625:16;:20;;;:39;;;179621:558;;179763:310;;;;;;;;-1:-1:-1;179763:310:0;;;;;;;;;;179884:23;;179763:310;;;;;;;;;179936:20;;;;179763:310;;;;;;179997:7;;;;179763:310;;;;;;;;;;;179727:33;;:16;;179744:15;;179727:33;;;;;;:::i;:::-;;;;;;:346;;;;180146:17;;;;:::i;:::-;;;179621:558;179342:848;179251:939;180312:9;180307:1500;180327:18;:25;180323:29;;180307:1500;;;180371:15;180389:18;180408:1;180389:21;;;;;;;;:::i;:::-;;;;;;;;;;;;;;-1:-1:-1;180429:21:0;;180425:1307;;180513:55;180621:7;180610:30;;;:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;180594:83;;;;;:73;880:55:1;;;180594:83:0;;;862:74:1;180594:73:0;;;;;;;835:18:1;;180594:83:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;180571:138;;;180513:196;;180820:9;180815:902;180835:24;:31;180831:1;:35;180815:902;;;180945:60;181008:24;181033:1;181008:27;;;;;;;;:::i;:::-;;;;;;;180945:90;;181147:364;;;;;;;;181202:17;:20;;;181147:364;;;;181256:17;:23;;;181147:364;;;;;;181314:17;:24;;;181147:364;;;;;;181370:17;:21;;;181147:364;;;;;;181428:7;181147:364;;;;;;181486:1;181147:364;;;181111:16;181128:15;181111:33;;;;;;;;:::i;:::-;;;;;;:400;;;;181592:17;;;;:::i;:::-;;-1:-1:-1;;181671:3:0;;180815:902;;;;180452:1280;180425:1307;-1:-1:-1;181777:3:0;;180307:1500;;;;181941:15;181911:46;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;181911:46:0;;;;;;;;;;;;;;;181895:62;;182009:9;182004:173;182024:13;:20;182020:1;:24;182004:173;;;182082:16;182099:1;182082:19;;;;;;;;:::i;:::-;;;;;;;182063:13;182077:1;182063:16;;;;;;;;:::i;:::-;;;;;;;;;;:38;182147:3;;182004:173;;;;175385:6799;;;175270:6914;;;:::o;186576:114::-;159411:5;;;;159397:10;:19;;;;:52;;-1:-1:-1;159434:15:0;;;;159420:10;:29;;159397:52;159393:85;;;159458:20;;;;;;;;;;;;;;159393:85;186652:15:::1;:30:::0;;;::::1;;::::0;;;::::1;::::0;;;::::1;::::0;;186576:114::o;161606:1006::-;161824:5;;:22;;;;;:5;880:55:1;;;161824:22:0;;;862:74:1;161668:16:0;;161824:5;;:15;;835:18:1;;161824:22:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;161917:10;;161813:33;;-1:-1:-1;161909:33:0;161917:10;161909:33;161905:78;;161956:10;;;:27;;;;;:10;880:55:1;;;161956:27:0;;;862:74:1;;;;161956:10:0;;;:20;;835:18:1;;161956:27:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;161944:39;;;;:::i;:::-;;;161905:78;162094:7;;162086:30;162094:7;162086:30;;;;162085:85;;-1:-1:-1;162130:24:0;;162122:47;162130:24;162122:47;;162085:85;162081:154;;;162199:7;;:24;;;;;:7;880:55:1;;;162199:24:0;;;862:74:1;162199:7:0;;;;:17;;835:18:1;;162199:24:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;162187:36;;;;:::i;:::-;;;162081:154;162307:9;162302:303;162322:18;:25;162318:29;;162302:303;;;162366:15;162384:18;162403:1;162384:21;;;;;;;;:::i;:::-;;;;;;;;;;;;;;-1:-1:-1;162424:21:0;;162420:110;;162478:36;;;;;:29;880:55:1;;;162478:36:0;;;862:74:1;162478:29:0;;;;;835:18:1;;162478:36:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;162466:48;;;;:::i;:::-;;;162420:110;-1:-1:-1;162575:3:0;;162302:303;;;;161606:1006;;;:::o;165016:231::-;165076:20;165109:42;165154:37;:35;:37::i;:::-;165217:22;;;;165016:231;-1:-1:-1;;165016:231:0:o;183708:698::-;159411:5;;;;159397:10;:19;;;;:52;;-1:-1:-1;159434:15:0;;;;159420:10;:29;;159397:52;159393:85;;;159458:20;;;;;;;;;;;;;;159393:85;183795:19:::1;::::0;::::1;183787:53;;;::::0;::::1;::::0;;10658:2:1;183787:53:0::1;::::0;::::1;10640:21:1::0;10697:2;10677:18;;;10670:30;10736:23;10716:18;;;10709:51;10777:18;;183787:53:0::1;10456:345:1::0;183787:53:0::1;183859:22;::::0;::::1;;::::0;;;:15:::1;:22;::::0;;;;;::::1;;:30;;:22:::0;:30:::1;183851:62;;;::::0;::::1;::::0;;20423:2:1;183851:62:0::1;::::0;::::1;20405:21:1::0;20462:2;20442:18;;;20435:30;20501:21;20481:18;;;20474:49;20540:18;;183851:62:0::1;20221:343:1::0;183851:62:0::1;183969:22;::::0;::::1;;::::0;;;:15:::1;:22;::::0;;;;183962:29;;;::::1;::::0;;184070:280:::1;184094:18;:25:::0;184090:29;::::1;184070:280;;;184170:5;184145:30;;:18;184164:1;184145:21;;;;;;;;:::i;:::-;;::::0;;;::::1;::::0;;;::::1;::::0;::::1;;:30:::0;184141:198:::1;;184228:1;184196:18;184215:1;184196:21;;;;;;;;:::i;:::-;;;;;;;;;:34;;;;;;;;;;;;;;;;;;184318:5;;184141:198;184121:3;;184070:280;;;-1:-1:-1::0;184367:31:0::1;::::0;892:42:1;880:55;;862:74;;184367:31:0::1;::::0;850:2:1;835:18;184367:31:0::1;683:259:1::0;93339:480:0;93537:45;;;93526:10;20111:55:1;;;93537:45:0;;;20093:74:1;20183:18;;;;20176:34;;;93537:45:0;;;;;;;;;;20066:18:1;;;;93537:45:0;;;;;;;;;;;;;93526:57;;-1:-1:-1;;;;93526:10:0;;;;:57;;93537:45;93526:57;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;93490:93;;;;93714:7;93713:8;:59;;;-1:-1:-1;93726:11:0;;:16;;;;:45;;;93758:4;93747:24;;;;;;;;;;;;:::i;:::-;93746:25;93726:45;93709:102;;;93781:30;;;;;;;;;;;;;;93709:102;93412:407;;93339:480;;;:::o;14:253:1:-;98:6;151:3;139:9;130:7;126:23;122:33;119:53;;;168:1;165;158:12;119:53;208:7;202:3;191:9;187:19;184:32;181:52;;;229:1;226;219:12;272:154;358:42;351:5;347:54;340:5;337:65;327:93;;416:1;413;406:12;431:247;490:6;543:2;531:9;522:7;518:23;514:32;511:52;;;559:1;556;549:12;511:52;598:9;585:23;617:31;642:5;617:31;:::i;:::-;667:5;431:247;-1:-1:-1;;;431:247:1:o;1621:660::-;1811:2;1823:21;;;1893:13;;1796:18;;;1915:22;;;1763:4;;1994:15;;;1968:2;1953:18;;;1763:4;2037:218;2051:6;2048:1;2045:13;2037:218;;;2116:13;;2131:42;2112:62;2100:75;;2204:2;2230:15;;;;2195:12;;;;2073:1;2066:9;2037:218;;;-1:-1:-1;2272:3:1;;1621:660;-1:-1:-1;;;;;1621:660:1:o;2286:226::-;2345:6;2398:2;2386:9;2377:7;2373:23;2369:32;2366:52;;;2414:1;2411;2404:12;2366:52;-1:-1:-1;2459:23:1;;2286:226;-1:-1:-1;2286:226:1:o;2517:184::-;2569:77;2566:1;2559:88;2666:4;2663:1;2656:15;2690:4;2687:1;2680:15;2706:253;2778:2;2772:9;2820:4;2808:17;;2855:18;2840:34;;2876:22;;;2837:62;2834:88;;;2902:18;;:::i;:::-;2938:2;2931:22;2706:253;:::o;2964:334::-;3035:2;3029:9;3091:2;3081:13;;3096:66;3077:86;3065:99;;3194:18;3179:34;;3215:22;;;3176:62;3173:88;;;3241:18;;:::i;:::-;3277:2;3270:22;2964:334;;-1:-1:-1;2964:334:1:o;3303:1025::-;3403:6;3411;3419;3472:3;3460:9;3451:7;3447:23;3443:33;3440:53;;;3489:1;3486;3479:12;3440:53;3528:9;3515:23;3547:31;3572:5;3547:31;:::i;:::-;3597:5;-1:-1:-1;3654:2:1;3639:18;;3626:32;3667:33;3626:32;3667:33;:::i;:::-;3719:7;-1:-1:-1;3764:2:1;3749:18;;3745:32;-1:-1:-1;3735:60:1;;3791:1;3788;3781:12;3735:60;3893:20;3870:3;3893:20;:::i;:::-;3935:3;3976;3965:9;3961:19;4003:7;3995:6;3992:19;3989:39;;;4024:1;4021;4014:12;3989:39;4063:2;4052:9;4048:18;4075:223;4091:6;4086:3;4083:15;4075:223;;;4173:3;4160:17;4190:33;4215:7;4190:33;:::i;:::-;4236:20;;4285:2;4276:12;;;;4108;4075:223;;;4079:3;;4317:5;4307:15;;;;3303:1025;;;;;:::o;5110:118::-;5196:5;5189:13;5182:21;5175:5;5172:32;5162:60;;5218:1;5215;5208:12;5233:382;5298:6;5306;5359:2;5347:9;5338:7;5334:23;5330:32;5327:52;;;5375:1;5372;5365:12;5327:52;5414:9;5401:23;5433:31;5458:5;5433:31;:::i;:::-;5483:5;-1:-1:-1;5540:2:1;5525:18;;5512:32;5553:30;5512:32;5553:30;:::i;:::-;5602:7;5592:17;;;5233:382;;;;;:::o;5620:1151::-;5892:2;5904:21;;;5974:13;;5877:18;;;5996:22;;;5844:4;;6075:15;;;6049:2;6034:18;;;5844:4;6118:627;6132:6;6129:1;6126:13;6118:627;;;6197:6;6191:13;6235:2;6229:9;6224:3;6217:22;6297:34;6291:2;6287;6283:11;6277:18;6273:59;6268:2;6263:3;6259:12;6252:81;6396:2;6392;6388:11;6382:18;6378:2;6367:34;6362:2;6357:3;6353:12;6346:56;6464:34;6456:4;6452:2;6448:13;6442:20;6438:61;6431:4;6426:3;6422:14;6415:85;6562:42;6554:4;6550:2;6546:13;6540:20;6536:69;6529:4;6524:3;6520:14;6513:93;6656:4;6652:2;6648:13;6642:20;6635:4;6630:3;6626:14;6619:44;;6692:4;6687:3;6683:14;6676:21;;6732:2;6724:6;6720:15;6710:25;;6154:1;6151;6147:9;6142:14;;6118:627;;6776:367;6844:6;6852;6905:2;6893:9;6884:7;6880:23;6876:32;6873:52;;;6921:1;6918;6911:12;6873:52;6960:9;6947:23;6979:31;7004:5;6979:31;:::i;:::-;7029:5;7107:2;7092:18;;;;7079:32;;-1:-1:-1;;;6776:367:1:o;8090:184::-;8142:77;8139:1;8132:88;8239:4;8236:1;8229:15;8263:4;8260:1;8253:15;10806:230;10876:6;10929:2;10917:9;10908:7;10904:23;10900:32;10897:52;;;10945:1;10942;10935:12;10897:52;-1:-1:-1;10990:16:1;;10806:230;-1:-1:-1;10806:230:1:o;11041:192::-;11120:13;;11173:34;11162:46;;11152:57;;11142:85;;11223:1;11220;11213:12;11142:85;11041:192;;;:::o;11238:208::-;11308:6;11361:2;11349:9;11340:7;11336:23;11332:32;11329:52;;;11377:1;11374;11367:12;11329:52;11400:40;11430:9;11400:40;:::i;11451:138::-;11530:13;;11552:31;11530:13;11552:31;:::i;11594:251::-;11664:6;11717:2;11705:9;11696:7;11692:23;11688:32;11685:52;;;11733:1;11730;11723:12;11685:52;11765:9;11759:16;11784:31;11809:5;11784:31;:::i;11850:166::-;11928:13;;11981:2;11970:21;;;11960:32;;11950:60;;12006:1;12003;11996:12;12021:1527;12107:5;12160:3;12153:4;12145:6;12141:17;12137:27;12127:55;;12178:1;12175;12168:12;12127:55;12211:6;12205:13;12255:4;12247:6;12243:17;12284:1;12306;12330:18;12322:6;12319:30;12316:56;;;12352:18;;:::i;:::-;12409:4;12400:6;12397:1;12393:14;12389:25;12381:33;;12434:21;12450:4;12434:21;:::i;:::-;12491:23;;;12589:1;12585:14;;;;12571:29;;;12423:32;-1:-1:-1;;12543:4:1;12530:18;;12612:15;;;12609:35;;;12640:1;12637;12630:12;12609:35;12697:6;12692:3;12689:15;12681:836;;;12766:1;12802:4;12796:3;12791;12787:13;12783:24;12780:44;;;12820:1;12817;12810:12;12780:44;12881:2;12875:9;12927:4;12915:17;;12966:18;12951:34;;12987:22;;;12948:62;12945:88;;;13013:18;;:::i;:::-;13053:2;13046:22;13149:10;;13172:23;;;13149:10;-1:-1:-1;13234:45:1;13273:4;13264:14;;13234:45;:::i;:::-;13227:4;13219:6;13215:17;13208:72;13317:42;13355:2;13350:3;13346:12;13317:42;:::i;:::-;13312:2;13304:6;13300:15;13293:67;13397:43;13436:2;13431:3;13427:12;13397:43;:::i;:::-;13392:2;13380:15;;13373:68;13454:19;;-1:-1:-1;12723:4:1;12714:14;;;;;13502:4;13493:14;12681:836;;;-1:-1:-1;13535:7:1;12021:1527;-1:-1:-1;;;;;12021:1527:1:o;13553:588::-;13613:5;13666:3;13659:4;13651:6;13647:17;13643:27;13633:55;;13684:1;13681;13674:12;13633:55;13785:19;13763:2;13785:19;:::i;:::-;13828:3;13866:2;13858:6;13854:15;13892:3;13884:6;13881:15;13878:35;;;13909:1;13906;13899:12;13878:35;13933:6;13948:162;13964:6;13959:3;13956:15;13948:162;;;14032:33;14061:3;14032:33;:::i;:::-;14020:46;;14095:4;14086:14;;;;13981;13948:162;;14146:1380;14254:6;14307:2;14295:9;14286:7;14282:23;14278:32;14275:52;;;14323:1;14320;14313:12;14275:52;14356:9;14350:16;14389:18;14381:6;14378:30;14375:50;;;14421:1;14418;14411:12;14375:50;14444:22;;14500:6;14482:16;;;14478:29;14475:49;;;14520:1;14517;14510:12;14475:49;14546:22;;:::i;:::-;14591:33;14621:2;14591:33;:::i;:::-;14577:48;;14684:2;14676:11;;;14670:18;14704:14;;;14697:31;14767:2;14759:11;;14753:18;14796;14783:32;;14780:52;;;14828:1;14825;14818:12;14780:52;14864:88;14944:7;14933:8;14929:2;14925:17;14864:88;:::i;:::-;14859:2;14852:5;14848:14;14841:112;;14992:2;14988;14984:11;14978:18;15021;15011:8;15008:32;15005:52;;;15053:1;15050;15043:12;15005:52;15089:88;15169:7;15158:8;15154:2;15150:17;15089:88;:::i;:::-;15084:2;15077:5;15073:14;15066:112;;15217:3;15213:2;15209:12;15203:19;15247:18;15237:8;15234:32;15231:52;;;15279:1;15276;15269:12;15231:52;15316:88;15396:7;15385:8;15381:2;15377:17;15316:88;:::i;:::-;15310:3;15303:5;15299:15;15292:113;;15438:57;15487:7;15481:3;15477:2;15473:12;15438:57;:::i;:::-;15432:3;15421:15;;15414:82;15425:5;14146:1380;-1:-1:-1;;;;14146:1380:1:o;16230:184::-;16282:77;16279:1;16272:88;16379:4;16376:1;16369:15;16403:4;16400:1;16393:15;16419:125;16484:9;;;16505:10;;;16502:36;;;16518:18;;:::i;:::-;16419:125;;;;:::o;16900:243::-;17022:34;17015:42;;;16971;;;16967:91;;17070:44;;17067:70;;;17117:18;;:::i;17456:195::-;17495:3;17526:66;17519:5;17516:77;17513:103;;17596:18;;:::i;:::-;-1:-1:-1;17643:1:1;17632:13;;17456:195::o;19041:175::-;19119:13;;19172:18;19161:30;;19151:41;;19141:69;;19206:1;19203;19196:12;19221:693;19322:6;19382:2;19370:9;19361:7;19357:23;19353:32;19397:2;19394:22;;;19412:1;19409;19402:12;19394:22;-1:-1:-1;19481:2:1;19475:9;19523:2;19511:15;;19556:18;19541:34;;19577:22;;;19538:62;19535:88;;;19603:18;;:::i;:::-;19639:2;19632:22;19678:40;19708:9;19678:40;:::i;:::-;19670:6;19663:56;19752:48;19796:2;19785:9;19781:18;19752:48;:::i;:::-;19747:2;19739:6;19735:15;19728:73;19834:48;19878:2;19867:9;19863:18;19834:48;:::i;:::-;19829:2;19817:15;;19810:73;19821:6;19221:693;-1:-1:-1;;;19221:693:1:o;20569:301::-;20698:3;20736:6;20730:13;20782:6;20775:4;20767:6;20763:17;20758:3;20752:37;20844:1;20808:16;;20833:13;;;-1:-1:-1;20808:16:1;20569:301;-1:-1:-1;20569:301:1:o;20875:245::-;20942:6;20995:2;20983:9;20974:7;20970:23;20966:32;20963:52;;;21011:1;21008;21001:12;20963:52;21043:9;21037:16;21062:28;21084:5;21062:28;:::i

Swarm Source

ipfs://906e77c6f61b3057feae5009f729232e2975ab0fb6ae39d9a4d084df7d210dc1

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

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.