Contract 0x98c58c1ceb01e198f8356763d5cba8eb7b11e4e2 2

 
Txn Hash Method
Block
From
To
Value [Txn Fee]
0x36f63fd78c940d05a6c51d08e986055e887eda6cbe77a5f7afde8f031ec88f50Transfer Ownersh...11151822021-09-17 4:37:39499 days 10 hrs ago0xfb59b91646cd0890f3e5343384feb746989b66c7 IN  0x98c58c1ceb01e198f8356763d5cba8eb7b11e4e20 ETH0.000489615214 ETH
0xda60a36f974bc6b766008af01385f5f2abaaa296d15645a4a1c588184dbf6babTransfer Ownersh...11151802021-09-17 4:37:39499 days 10 hrs ago0xfb59b91646cd0890f3e5343384feb746989b66c7 IN  0x98c58c1ceb01e198f8356763d5cba8eb7b11e4e20 ETH0.000491572713 ETH
0x24aaba8a27105cfd3485299ee55e94978378b5dc30cb5bfc3453ab0fd7edbaf2Transfer Ownersh...11151772021-09-17 4:37:15499 days 10 hrs ago0xfb59b91646cd0890f3e5343384feb746989b66c7 IN  0x98c58c1ceb01e198f8356763d5cba8eb7b11e4e20 ETH0.000490493252 ETH
0xde655f9232534da2400032931f031827ec1cea2187c3c5bd57dc2aeb5e988b78Deploy Pool10099462021-09-16 3:44:11500 days 11 hrs ago0xfb59b91646cd0890f3e5343384feb746989b66c7 IN  0x98c58c1ceb01e198f8356763d5cba8eb7b11e4e20 ETH0.005738276488 ETH
0x11e7afb598bf8990ca2e1709483a207db851c79518a604195919875c943f639cDeploy Pool10099302021-09-16 3:43:14500 days 11 hrs ago0xfb59b91646cd0890f3e5343384feb746989b66c7 IN  0x98c58c1ceb01e198f8356763d5cba8eb7b11e4e20 ETH0.005738231088 ETH
0xc8aee9ba75327576a1ace1cb48d1516a4fdb769bd512bea0a0596d06994d6897Deploy Pool10099102021-09-16 3:43:14500 days 11 hrs ago0xfb59b91646cd0890f3e5343384feb746989b66c7 IN  0x98c58c1ceb01e198f8356763d5cba8eb7b11e4e20 ETH0.00573819924 ETH
0x5e9fc4c413ad2fc30a954f95fee8331efe07a0a7d7cfe202d200d92b28cdf151Deploy Pool10098832021-09-16 3:43:14500 days 11 hrs ago0xfb59b91646cd0890f3e5343384feb746989b66c7 IN  0x98c58c1ceb01e198f8356763d5cba8eb7b11e4e20 ETH0.006054084151 ETH
0x22e3fcb6720df167801afe5401ce566750b1efc22c48646ad59de2a4aa9ae171Set Pool Committ...10098582021-09-16 3:43:14500 days 11 hrs ago0xfb59b91646cd0890f3e5343384feb746989b66c7 IN  0x98c58c1ceb01e198f8356763d5cba8eb7b11e4e20 ETH0.000468271979 ETH
0xf61e739db7edd2abb9e093d84184d396fcbe342437a70dd985c95f6f458b0ea3Set Fee10098482021-09-16 3:43:14500 days 11 hrs ago0xfb59b91646cd0890f3e5343384feb746989b66c7 IN  0x98c58c1ceb01e198f8356763d5cba8eb7b11e4e20 ETH0.000590658536 ETH
0xc0e2644329633279eb84379f4c13c3db3ad3527bac0ffa291f2df205c73c9c85Set Pool Keeper10098222021-09-16 3:41:56500 days 11 hrs ago0xfb59b91646cd0890f3e5343384feb746989b66c7 IN  0x98c58c1ceb01e198f8356763d5cba8eb7b11e4e20 ETH0.000603803495 ETH
0xe009d2a0acb1c95d3ea33482b4675360764ab7807b76d9f356cb0b550a7aba9d0x60c0604010097492021-09-16 3:41:36500 days 11 hrs ago0xfb59b91646cd0890f3e5343384feb746989b66c7 IN  Create: PoolFactory0 ETH0.05778951327 ETH
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0x335376258edb6fc4f4b2ee21f513308db3c907edcfbde41d9d1a7fbc693d808b563941742023-01-29 15:28:315 mins ago 0x759e817f0c40b11c775d1071d466b5ff5c6ce28e 0x98c58c1ceb01e198f8356763d5cba8eb7b11e4e20 ETH
0x335376258edb6fc4f4b2ee21f513308db3c907edcfbde41d9d1a7fbc693d808b563941742023-01-29 15:28:315 mins ago 0x759e817f0c40b11c775d1071d466b5ff5c6ce28e 0x98c58c1ceb01e198f8356763d5cba8eb7b11e4e20 ETH
0x335376258edb6fc4f4b2ee21f513308db3c907edcfbde41d9d1a7fbc693d808b563941742023-01-29 15:28:315 mins ago 0x759e817f0c40b11c775d1071d466b5ff5c6ce28e 0x98c58c1ceb01e198f8356763d5cba8eb7b11e4e20 ETH
0x335376258edb6fc4f4b2ee21f513308db3c907edcfbde41d9d1a7fbc693d808b563941742023-01-29 15:28:315 mins ago 0x759e817f0c40b11c775d1071d466b5ff5c6ce28e 0x98c58c1ceb01e198f8356763d5cba8eb7b11e4e20 ETH
0x69859e1d875bc7cd4ef1b1b859f27e367b92d01f31f8144fa7b796e1ae609b96563941742023-01-29 15:28:315 mins ago 0x759e817f0c40b11c775d1071d466b5ff5c6ce28e 0x98c58c1ceb01e198f8356763d5cba8eb7b11e4e20 ETH
0x69859e1d875bc7cd4ef1b1b859f27e367b92d01f31f8144fa7b796e1ae609b96563941742023-01-29 15:28:315 mins ago 0x759e817f0c40b11c775d1071d466b5ff5c6ce28e 0x98c58c1ceb01e198f8356763d5cba8eb7b11e4e20 ETH
0x69859e1d875bc7cd4ef1b1b859f27e367b92d01f31f8144fa7b796e1ae609b96563941742023-01-29 15:28:315 mins ago 0x759e817f0c40b11c775d1071d466b5ff5c6ce28e 0x98c58c1ceb01e198f8356763d5cba8eb7b11e4e20 ETH
0x69859e1d875bc7cd4ef1b1b859f27e367b92d01f31f8144fa7b796e1ae609b96563941742023-01-29 15:28:315 mins ago 0x759e817f0c40b11c775d1071d466b5ff5c6ce28e 0x98c58c1ceb01e198f8356763d5cba8eb7b11e4e20 ETH
0xabaad96576185aa11eee831d9eb9123ff93cd851d4d3945978e7cb0e2461f6b2563941742023-01-29 15:28:315 mins ago 0x759e817f0c40b11c775d1071d466b5ff5c6ce28e 0x98c58c1ceb01e198f8356763d5cba8eb7b11e4e20 ETH
0xabaad96576185aa11eee831d9eb9123ff93cd851d4d3945978e7cb0e2461f6b2563941742023-01-29 15:28:315 mins ago 0x759e817f0c40b11c775d1071d466b5ff5c6ce28e 0x98c58c1ceb01e198f8356763d5cba8eb7b11e4e20 ETH
0xabaad96576185aa11eee831d9eb9123ff93cd851d4d3945978e7cb0e2461f6b2563941742023-01-29 15:28:315 mins ago 0x759e817f0c40b11c775d1071d466b5ff5c6ce28e 0x98c58c1ceb01e198f8356763d5cba8eb7b11e4e20 ETH
0xabaad96576185aa11eee831d9eb9123ff93cd851d4d3945978e7cb0e2461f6b2563941742023-01-29 15:28:315 mins ago 0x759e817f0c40b11c775d1071d466b5ff5c6ce28e 0x98c58c1ceb01e198f8356763d5cba8eb7b11e4e20 ETH
0x3a989e988c3e7b3dfd40a815f8487c2c85ff28ba5fce5cdd9f48d7871c6fa79d563941742023-01-29 15:28:315 mins ago 0x759e817f0c40b11c775d1071d466b5ff5c6ce28e 0x98c58c1ceb01e198f8356763d5cba8eb7b11e4e20 ETH
0x3a989e988c3e7b3dfd40a815f8487c2c85ff28ba5fce5cdd9f48d7871c6fa79d563941742023-01-29 15:28:315 mins ago 0x759e817f0c40b11c775d1071d466b5ff5c6ce28e 0x98c58c1ceb01e198f8356763d5cba8eb7b11e4e20 ETH
0x3a989e988c3e7b3dfd40a815f8487c2c85ff28ba5fce5cdd9f48d7871c6fa79d563941742023-01-29 15:28:315 mins ago 0x759e817f0c40b11c775d1071d466b5ff5c6ce28e 0x98c58c1ceb01e198f8356763d5cba8eb7b11e4e20 ETH
0x3a989e988c3e7b3dfd40a815f8487c2c85ff28ba5fce5cdd9f48d7871c6fa79d563941742023-01-29 15:28:315 mins ago 0x759e817f0c40b11c775d1071d466b5ff5c6ce28e 0x98c58c1ceb01e198f8356763d5cba8eb7b11e4e20 ETH
0x58e5f291f0b65e37a25b96248a491ce526b71eb39a0f9744de80abc84184fdab563868872023-01-29 14:54:1940 mins ago 0x759e817f0c40b11c775d1071d466b5ff5c6ce28e 0x98c58c1ceb01e198f8356763d5cba8eb7b11e4e20 ETH
0xe5dfb79e3783acac068473a77c2154a3fdfbd3c1274ffd3ac2fbda63bb2613d4563868872023-01-29 14:54:1940 mins ago 0x759e817f0c40b11c775d1071d466b5ff5c6ce28e 0x98c58c1ceb01e198f8356763d5cba8eb7b11e4e20 ETH
0xea6c0c18da09a875352839c8dacab0e4c09fa9f26734e06f68264e75379ac098563868872023-01-29 14:54:1940 mins ago 0x759e817f0c40b11c775d1071d466b5ff5c6ce28e 0x98c58c1ceb01e198f8356763d5cba8eb7b11e4e20 ETH
0x288a19af3dc2a63a1f142eeab21b1c7c31b3164df698b328442e9e34bd9f5998563868872023-01-29 14:54:1940 mins ago 0x759e817f0c40b11c775d1071d466b5ff5c6ce28e 0x98c58c1ceb01e198f8356763d5cba8eb7b11e4e20 ETH
0xe11488b281c75de8af040a4368a3e2058b67293595bdf883a5bb7566d1639177563812532023-01-29 14:28:311 hr 5 mins ago 0x759e817f0c40b11c775d1071d466b5ff5c6ce28e 0x98c58c1ceb01e198f8356763d5cba8eb7b11e4e20 ETH
0xe11488b281c75de8af040a4368a3e2058b67293595bdf883a5bb7566d1639177563812532023-01-29 14:28:311 hr 5 mins ago 0x759e817f0c40b11c775d1071d466b5ff5c6ce28e 0x98c58c1ceb01e198f8356763d5cba8eb7b11e4e20 ETH
0xe11488b281c75de8af040a4368a3e2058b67293595bdf883a5bb7566d1639177563812532023-01-29 14:28:311 hr 5 mins ago 0x759e817f0c40b11c775d1071d466b5ff5c6ce28e 0x98c58c1ceb01e198f8356763d5cba8eb7b11e4e20 ETH
0xe11488b281c75de8af040a4368a3e2058b67293595bdf883a5bb7566d1639177563812532023-01-29 14:28:311 hr 5 mins ago 0x759e817f0c40b11c775d1071d466b5ff5c6ce28e 0x98c58c1ceb01e198f8356763d5cba8eb7b11e4e20 ETH
0x6b02423d0dbc996e6ceb593265678a0de40f724ab6ff4cc134bafb3a64e8f507563812532023-01-29 14:28:311 hr 5 mins ago 0x759e817f0c40b11c775d1071d466b5ff5c6ce28e 0x98c58c1ceb01e198f8356763d5cba8eb7b11e4e20 ETH
[ Download CSV Export 
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.

Contract Source Code Verified (Exact Match)

Contract Name:
PoolFactory

Compiler Version
v0.8.7+commit.e28d00a7

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 27 : PoolFactory.sol
//SPDX-License-Identifier: CC-BY-NC-ND-4.0
pragma solidity 0.8.7;

import "../interfaces/IPoolFactory.sol";
import "../interfaces/ILeveragedPool.sol";
import "../interfaces/IPoolCommitterDeployer.sol";
import "../interfaces/IPoolCommitter.sol";
import "../interfaces/IERC20DecimalsWrapper.sol";
import "./LeveragedPool.sol";
import "./PoolToken.sol";
import "./PoolKeeper.sol";
import "@openzeppelin/contracts/proxy/Clones.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

/// @title The pool factory contract
contract PoolFactory is IPoolFactory, Ownable {
    // #### Globals
    PoolToken public pairTokenBase;
    address public immutable pairTokenBaseAddress;
    LeveragedPool public poolBase;
    address public immutable poolBaseAddress;
    IPoolKeeper public poolKeeper;
    IPoolCommitterDeployer public poolCommitterDeployer;

    // Default max leverage of 10
    uint16 public maxLeverage = 10;
    // Contract address to receive protocol fees
    address public feeReceiver;
    // Default fee; Fee value as a decimal multiplied by 10^18. For example, 0.5% is represented as 0.5 * 10^18
    uint256 public fee;

    // This is required because we must pass along *some* value for decimal
    // precision to the base pool tokens as we use the Cloneable pattern
    uint8 constant DEFAULT_NUM_DECIMALS = 18;

    /**
     * @notice Format: Pool counter => pool address
     */
    mapping(uint256 => address) public override pools;
    uint256 public override numPools;

    /**
     * @notice Format: Pool address => validity
     */
    mapping(address => bool) public override isValidPool;

    // #### Functions
    constructor(address _feeReceiver) {
        // Deploy base contracts
        pairTokenBase = new PoolToken(DEFAULT_NUM_DECIMALS);
        pairTokenBaseAddress = address(pairTokenBase);
        poolBase = new LeveragedPool();
        poolBaseAddress = address(poolBase);

        ILeveragedPool.Initialization memory baseInitialization = ILeveragedPool.Initialization(
            address(this),
            address(this),
            address(this),
            address(this),
            address(this),
            address(this),
            address(this),
            "BASE_POOL",
            15,
            30,
            0,
            1,
            address(this),
            address(this)
        );
        // Init bases
        poolBase.initialize(baseInitialization);

        pairTokenBase.initialize(address(this), "BASE_TOKEN", "BASE", DEFAULT_NUM_DECIMALS);
        feeReceiver = _feeReceiver;
    }

    /**
     * @notice Deploy a leveraged pool with given parameters
     * @param deploymentParameters Deployment parameters of the market. Some may be reconfigurable
     * @return Address of the created pool
     */
    function deployPool(PoolDeployment calldata deploymentParameters) external override onlyGov returns (address) {
        address _poolKeeper = address(poolKeeper);
        require(_poolKeeper != address(0), "PoolKeeper not set");
        require(address(poolCommitterDeployer) != address(0), "PoolCommitterDeployer not set");
        address poolCommitter = poolCommitterDeployer.deploy(
            deploymentParameters.minimumCommitSize,
            deploymentParameters.maximumCommitQueueLength
        );
        require(
            deploymentParameters.leverageAmount >= 1 && deploymentParameters.leverageAmount <= maxLeverage,
            "PoolKeeper: leveraged amount invalid"
        );
        require(IERC20DecimalsWrapper(deploymentParameters.quoteToken).decimals() <= 18, "Token decimals > 18");
        LeveragedPool pool = LeveragedPool(Clones.clone(poolBaseAddress));
        address _pool = address(pool);
        emit DeployPool(_pool, deploymentParameters.poolName);

        string memory leverage = uint2str(deploymentParameters.leverageAmount);
        string memory longString = string(abi.encodePacked(leverage, "L-", deploymentParameters.poolName));
        string memory shortString = string(abi.encodePacked(leverage, "S-", deploymentParameters.poolName));

        uint8 settlementDecimals = IERC20DecimalsWrapper(deploymentParameters.quoteToken).decimals();
        address shortToken = deployPairToken(_pool, shortString, shortString, settlementDecimals);
        address longToken = deployPairToken(_pool, longString, longString, settlementDecimals);
        ILeveragedPool.Initialization memory initialization = ILeveragedPool.Initialization(
            owner(), // governance is the owner of pools -- if this changes, `onlyGov` breaks
            _poolKeeper,
            deploymentParameters.oracleWrapper,
            deploymentParameters.settlementEthOracle,
            longToken,
            shortToken,
            poolCommitter,
            string(abi.encodePacked(leverage, "-", deploymentParameters.poolName)),
            deploymentParameters.frontRunningInterval,
            deploymentParameters.updateInterval,
            fee,
            deploymentParameters.leverageAmount,
            feeReceiver,
            deploymentParameters.quoteToken
        );

        // approve the quote token on the pool committer to finalise linking
        // this also stores the pool address in the committer
        // finalise pool setup
        pool.initialize(initialization);
        // approve the quote token on the pool commiter to finalise linking
        // this also stores the pool address in the commiter
        IPoolCommitter(poolCommitter).setQuoteAndPool(deploymentParameters.quoteToken, _pool);
        poolKeeper.newPool(_pool);
        pools[numPools] = _pool;
        numPools += 1;
        isValidPool[_pool] = true;
        return _pool;
    }

    /**
     * @notice Deploy a contract for pool tokens
     * @param name Name of the token
     * @param symbol Symbol of the token
     * @param decimals Number of decimal places to be supported
     * @return Address of the pool token
     */
    function deployPairToken(
        address owner,
        string memory name,
        string memory symbol,
        uint8 decimals
    ) internal returns (address) {
        PoolToken pairToken = PoolToken(Clones.clone(pairTokenBaseAddress));
        pairToken.initialize(owner, name, symbol, decimals);

        return address(pairToken);
    }

    function setPoolKeeper(address _poolKeeper) external override onlyOwner {
        require(_poolKeeper != address(0), "address cannot be null");
        poolKeeper = IPoolKeeper(_poolKeeper);
    }

    function setMaxLeverage(uint16 newMaxLeverage) external override onlyOwner {
        require(newMaxLeverage > 0, "Maximum leverage must be non-zero");
        maxLeverage = newMaxLeverage;
    }

    function setFeeReceiver(address _feeReceiver) external override onlyOwner {
        require(_feeReceiver != address(0), "address cannot be null");
        feeReceiver = _feeReceiver;
    }

    /**
     * @notice Set the fee amount. This is a percentage multiplied by 10^18.
     *         e.g. 5% is 0.05 * 10^18
     * @param _fee The fee amount as a percentage multiplied by 10^18
     */
    function setFee(uint256 _fee) external override onlyOwner {
        fee = _fee;
    }

    function setPoolCommitterDeployer(address _poolCommitterDeployer) external override onlyOwner {
        require(_poolCommitterDeployer != address(0), "address cannot be null");
        poolCommitterDeployer = IPoolCommitterDeployer(_poolCommitterDeployer);
    }

    function getOwner() external view override returns (address) {
        return owner();
    }

    /**
     * @notice Converts a uint to a str
     * @dev Assumes ASCII strings
     * @return raw string representation of the uint
     */
    function uint2str(uint256 _i) internal pure returns (string memory) {
        if (_i == 0) {
            return "0";
        }
        uint256 j = _i;
        uint256 len;
        while (j != 0) {
            len++;
            j /= 10;
        }
        bytes memory bstr = new bytes(len);
        uint256 k = len;
        while (_i != 0) {
            k = k - 1;
            uint8 temp = (48 + uint8(_i - (_i / 10) * 10));
            bytes1 b1 = bytes1(temp);
            bstr[k] = b1;
            _i /= 10;
        }
        return string(bstr);
    }

    modifier onlyGov() {
        require(msg.sender == owner(), "msg.sender not governance");
        _;
    }
}

File 2 of 27 : IPoolFactory.sol
//SPDX-License-Identifier: CC-BY-NC-ND-4.0
pragma solidity 0.8.7;

/// @title The contract factory for the keeper and pool contracts. Utilizes minimal clones to keep gas costs low
interface IPoolFactory {
    struct PoolDeployment {
        string poolName; // The name to identify a pool by
        uint32 frontRunningInterval; // The minimum number of seconds that must elapse before a commit can be executed. Must be smaller than or equal to the update interval to prevent deadlock
        uint32 updateInterval; // The minimum number of seconds that must elapse before a price change
        uint16 leverageAmount; // The amount of exposure to price movements for the pool
        address quoteToken; // The digital asset that the pool accepts
        address oracleWrapper; // The IOracleWrapper implementation for fetching price feed data
        address settlementEthOracle; // The oracle to fetch the price of Ether in terms of the settlement token
        uint128 minimumCommitSize; // The minimum amount (in settlement tokens) that a user can commit in a single commitment
        uint128 maximumCommitQueueLength; // The maximum number of commitments that can be made for a given updateInterval
    }

    // #### Events
    /**
     * @notice Creates a notification when a pool is deployed
     * @param pool Address of the new pool
     * @param ticker Ticker of the neew pool
     */
    event DeployPool(address indexed pool, string ticker);

    // #### Getters for Globals
    function pools(uint256 id) external view returns (address);

    function numPools() external view returns (uint256);

    function isValidPool(address _pool) external view returns (bool);

    // #### Functions
    function deployPool(PoolDeployment calldata deploymentParameters) external returns (address);

    function getOwner() external returns (address);

    function setPoolKeeper(address _poolKeeper) external;

    function setMaxLeverage(uint16 newMaxLeverage) external;

    function setFeeReceiver(address _feeReceiver) external;

    function setFee(uint256 _fee) external;

    function setPoolCommitterDeployer(address _poolCommitterDeployer) external;
}

File 3 of 27 : ILeveragedPool.sol
//SPDX-License-Identifier: CC-BY-NC-ND-4.0
pragma solidity 0.8.7;

/// @title The pool controller contract interface
interface ILeveragedPool {
    // Initialisation parameters for new market
    struct Initialization {
        address _owner; // Owner of the contract
        address _keeper; // The address of the PoolKeeper contract
        address _oracleWrapper; // The oracle wrapper for the derivative price feed
        address _settlementEthOracle; // The oracle wrapper for the SettlementToken/ETH price feed
        address _longToken; // Address of the long pool token
        address _shortToken; // Address of the short pool token
        address _poolCommitter; // Address of the PoolCommitter contract
        string _poolName; // The pool identification name
        uint32 _frontRunningInterval; // The minimum number of seconds that must elapse before a commit is forced to wait until the next interval
        uint32 _updateInterval; // The minimum number of seconds that must elapse before a commit can be executed
        uint256 _fee; // The fund movement fee. This amount is extracted from the deposited asset with every update and sent to the fee address
        uint16 _leverageAmount; // The amount of exposure to price movements for the pool
        address _feeAddress; // The address that the fund movement fee is sent to
        address _quoteToken; //  The digital asset that the pool accepts. Must have a decimals() function
    }

    // #### Events
    /**
     * @notice Creates a notification when the pool is setup and ready for use
     * @param longToken The address of the LONG pair token
     * @param shortToken The address of the SHORT pair token
     * @param quoteToken The address of the digital asset that the pool accepts
     * @param poolName The pool code for the pool
     */
    event PoolInitialized(address indexed longToken, address indexed shortToken, address quoteToken, string poolName);

    /**
     * @notice Creates a notification when the pool is rebalanced
     * @param shortBalanceChange The change of funds in the short side
     * @param longBalanceChange The change of funds in the long side
     */
    event PoolRebalance(int256 shortBalanceChange, int256 longBalanceChange);

    /**
     * @notice Creates a notification when the pool's price execution fails
     * @param startPrice Price prior to price change execution
     * @param endPrice Price during price change execution
     */
    event PriceChangeError(int256 indexed startPrice, int256 indexed endPrice);

    /**
     * @notice Represents change in fee receiver's address
     * @param oldAddress Previous address
     * @param newAddress Address after change
     */
    event FeeAddressUpdated(address indexed oldAddress, address indexed newAddress);

    /**
     * @notice Represents change in keeper's address
     * @param oldAddress Previous address
     * @param newAddress Address after change
     */
    event KeeperAddressChanged(address indexed oldAddress, address indexed newAddress);

    /**
     * @notice Represents proposed change in governance address
     * @param newAddress Proposed address
     */
    event ProvisionalGovernanceChanged(address indexed newAddress);

    /**
     * @notice Represents change in governance address
     * @param oldAddress Previous address
     * @param newAddress Address after change
     */
    event GovernanceAddressChanged(address indexed oldAddress, address indexed newAddress);

    function leverageAmount() external view returns (bytes16);

    function poolCommitter() external view returns (address);

    function quoteToken() external view returns (address);

    function oracleWrapper() external view returns (address);

    function lastPriceTimestamp() external view returns (uint256);

    function poolName() external view returns (string calldata);

    function updateInterval() external view returns (uint32);

    function shortBalance() external view returns (uint256);

    function longBalance() external view returns (uint256);

    function frontRunningInterval() external view returns (uint32);

    function poolTokens() external view returns (address[2] memory);

    function settlementEthOracle() external view returns (address);

    // #### Functions
    /**
     * @notice Configures the pool on deployment. The pools are EIP 1167 clones.
     * @dev This should only be able to be run once to prevent abuse of the pool. Use of Openzeppelin Initializable or similar is recommended
     * @param initialization The struct Initialization containing initialization data
     */
    function initialize(Initialization calldata initialization) external;

    function poolUpkeep(int256 _oldPrice, int256 _newPrice) external;

    function quoteTokenTransferFrom(
        address from,
        address to,
        uint256 amount
    ) external;

    function payKeeperFromBalances(address to, uint256 amount) external returns (bool);

    function quoteTokenTransfer(address to, uint256 amount) external;

    function setNewPoolBalances(uint256 _longBalance, uint256 _shortBalance) external;

    /**
     * @return _latestPrice The oracle price
     * @return _data The oracleWrapper's metadata. Implementations can choose what data to return here
     * @return _lastPriceTimestamp The timestamp of the last upkeep
     * @return _updateInterval The update frequency for this pool
     * @dev To save gas so PoolKeeper does not have to make three external calls
     */
    function getUpkeepInformation()
        external
        view
        returns (
            int256 _latestPrice,
            bytes memory _data,
            uint256 _lastPriceTimestamp,
            uint256 _updateInterval
        );

    function getOraclePrice() external view returns (int256);

    function intervalPassed() external view returns (bool);

    function balances() external view returns (uint256 _shortBalance, uint256 _longBalance);

    function setKeeper(address _keeper) external;

    function transferGovernance(address _governance) external;

    function claimGovernance() external;

    function updateFeeAddress(address account) external;

    function mintTokens(
        uint256 token,
        uint256 amount,
        address burner
    ) external;

    function burnTokens(
        uint256 token,
        uint256 amount,
        address burner
    ) external;
}

File 4 of 27 : IPoolCommitterDeployer.sol
//SPDX-License-Identifier: CC-BY-NC-ND-4.0
pragma solidity 0.8.7;

/// @title The PoolCommitterDeployer interface
interface IPoolCommitterDeployer {
    function deploy(uint128 _minimumCommitSize, uint128 _maximumCommitQueueLength) external returns (address);
}

File 5 of 27 : IPoolCommitter.sol
//SPDX-License-Identifier: CC-BY-NC-ND-4.0
pragma solidity 0.8.7;

/// @title The interface for the contract that handles pool commitments
interface IPoolCommitter {
    /// Type of commit
    enum CommitType {
        ShortMint,
        ShortBurn,
        LongMint,
        LongBurn
    }

    // Commit information
    struct Commit {
        uint256 amount;
        CommitType commitType;
        uint40 created;
        address owner;
    }

    /**
     * @notice Creates a notification when a commit is created
     * @param commitID ID of the commit
     * @param amount Amount of the commit
     * @param commitType Type of the commit (Short v Long, Mint v Burn)
     */
    event CreateCommit(uint128 indexed commitID, uint256 indexed amount, CommitType indexed commitType);

    /**
     * @notice Creates a notification when a commit is removed (uncommitted)
     * @param commitID ID of the commit
     * @param amount Amount of the commit
     * @param commitType Type of the commit (Short v Long, Mint v Burn)
     */
    event RemoveCommit(uint128 indexed commitID, uint256 indexed amount, CommitType indexed commitType);

    /**
     * @notice Creates a notification when a commit is executed
     * @param commitID ID of the commit that's executed
     */
    event ExecuteCommit(uint128 commitID);

    /**
     * @notice Creates a notification when a commit fails to execute
     * @param commitID ID of the commit
     */
    event FailedCommitExecution(uint128 commitID);

    // #### Functions

    function commit(CommitType commitType, uint256 amount) external;

    function executeAllCommitments() external;

    function executeCommitment(Commit memory _commit) external;

    function getCommit(uint128 _commitID) external view returns (Commit memory);

    function setQuoteAndPool(address quoteToken, address leveragedPool) external;

    function setMinimumCommitSize(uint128 _minimumCommitSize) external;

    function setMaxCommitQueueLength(uint128 _maximumCommitQueueLength) external;
}

File 6 of 27 : IERC20DecimalsWrapper.sol
//SPDX-License-Identifier: CC-BY-NC-ND-4.0
pragma solidity 0.8.7;

/// @title The decimals interface for extending the ERC20 interface
interface IERC20DecimalsWrapper {
    function decimals() external view returns (uint8);
}

File 7 of 27 : LeveragedPool.sol
//SPDX-License-Identifier: CC-BY-NC-ND-4.0
pragma solidity 0.8.7;

import "../interfaces/ILeveragedPool.sol";
import "../interfaces/IPoolCommitter.sol";
import "../interfaces/IPoolToken.sol";
import "@openzeppelin/contracts/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

import "./PoolSwapLibrary.sol";
import "../interfaces/IOracleWrapper.sol";

/// @title The pool contract itself
contract LeveragedPool is ILeveragedPool, Initializable {
    using SafeERC20 for IERC20;
    // #### Globals

    // Each balance is the amount of quote tokens in the pair
    uint256 public override shortBalance;
    uint256 public override longBalance;
    uint32 public override frontRunningInterval;
    uint32 public override updateInterval;

    bytes16 public fee;
    bytes16 public override leverageAmount;

    // Index 0 is the LONG token, index 1 is the SHORT token
    address[2] public tokens;

    address public governance;
    address public keeper;
    address public feeAddress;
    address public override quoteToken;
    address public override poolCommitter;
    uint256 public override lastPriceTimestamp; // The last time the pool was upkept

    string public override poolName;
    address public override oracleWrapper;
    address public override settlementEthOracle;

    address public provisionalGovernance;
    bool public governanceTransferInProgress;
    bool public paused;

    event Paused();
    event Unpaused();

    // #### Functions

    function initialize(ILeveragedPool.Initialization calldata initialization) external override initializer {
        require(initialization._feeAddress != address(0), "Fee address cannot be 0 address");
        require(initialization._quoteToken != address(0), "Quote token cannot be 0 address");
        require(initialization._oracleWrapper != address(0), "Oracle wrapper cannot be 0 address");
        require(initialization._settlementEthOracle != address(0), "Keeper oracle cannot be 0 address");
        require(initialization._owner != address(0), "Owner cannot be 0 address");
        require(initialization._keeper != address(0), "Keeper cannot be 0 address");
        require(initialization._longToken != address(0), "Long token cannot be 0 address");
        require(initialization._shortToken != address(0), "Short token cannot be 0 address");
        require(initialization._poolCommitter != address(0), "PoolCommitter cannot be 0 address");
        require(initialization._frontRunningInterval < initialization._updateInterval, "frontRunning > updateInterval");

        require(initialization._fee < 1 * PoolSwapLibrary.WAD_PRECISION, "Fee >= 100%");

        // set the owner of the pool. This is governance when deployed from the factory
        governance = initialization._owner;

        // Setup variables
        keeper = initialization._keeper;
        oracleWrapper = initialization._oracleWrapper;
        settlementEthOracle = initialization._settlementEthOracle;
        quoteToken = initialization._quoteToken;
        frontRunningInterval = initialization._frontRunningInterval;
        updateInterval = initialization._updateInterval;
        fee = PoolSwapLibrary.convertUIntToDecimal(initialization._fee);
        leverageAmount = PoolSwapLibrary.convertUIntToDecimal(initialization._leverageAmount);
        feeAddress = initialization._feeAddress;
        lastPriceTimestamp = block.timestamp;
        poolName = initialization._poolName;
        tokens[0] = initialization._longToken;
        tokens[1] = initialization._shortToken;
        poolCommitter = initialization._poolCommitter;
        emit PoolInitialized(
            initialization._longToken,
            initialization._shortToken,
            initialization._quoteToken,
            initialization._poolName
        );
    }

    /**
     * @notice Execute a price change, then execute all commits in PoolCommitter
     * @dev This is the entry point to upkeep a market
     */
    function poolUpkeep(int256 _oldPrice, int256 _newPrice) external override onlyKeeper onlyUnpaused {
        require(intervalPassed(), "Update interval hasn't passed");
        // perform price change and update pool balances
        executePriceChange(_oldPrice, _newPrice);
        // execute pending commitments to enter and exit the pool
        IPoolCommitter(poolCommitter).executeAllCommitments();
        lastPriceTimestamp = block.timestamp;
    }

    /**
     * @notice Pay keeper some amount in the collateral token for the perpetual pools market
     * @param to Address of the pool keeper to pay
     * @param amount Amount to pay the pool keeper
     * @return Whether the keeper is going to be paid; false if the amount exceeds the balances of the
     *         long and short pool, and true if the keeper can successfully be paid out
     */
    function payKeeperFromBalances(address to, uint256 amount)
        external
        override
        onlyKeeper
        onlyUnpaused
        returns (bool)
    {
        require(to != address(0), "Receipient address cannot be null");
        uint256 _shortBalance = shortBalance;
        uint256 _longBalance = longBalance;

        // If the rewards are more than the balances of the pool, the keeper does not get paid
        if (amount >= _shortBalance + _longBalance) {
            return false;
        }

        (uint256 shortBalanceAfterRewards, uint256 longBalanceAfterRewards) = PoolSwapLibrary.getBalancesAfterFees(
            amount,
            _shortBalance,
            _longBalance
        );

        shortBalance = shortBalanceAfterRewards;
        longBalance = longBalanceAfterRewards;

        // Pay keeper
        IERC20(quoteToken).safeTransfer(to, amount);

        return true;
    }

    /**
     * @notice Transfer tokens from pool to user
     * @param to Address of account to transfer to
     * @param amount Amount of quote tokens being transferred
     */
    function quoteTokenTransfer(address to, uint256 amount) external override onlyPoolCommitter onlyUnpaused {
        require(to != address(0), "To address cannot be 0 address");
        IERC20(quoteToken).safeTransfer(to, amount);
    }

    /**
     * @notice Transfer tokens from user to account
     * @param from The account that's transferring quote tokens
     * @param to Address of account to transfer to
     * @param amount Amount of quote tokens being transferred
     */
    function quoteTokenTransferFrom(
        address from,
        address to,
        uint256 amount
    ) external override onlyPoolCommitter onlyUnpaused {
        require(from != address(0), "From address cannot be 0 address");
        require(to != address(0), "To address cannot be 0 address");
        IERC20(quoteToken).safeTransferFrom(from, to, amount);
    }

    /**
     * @notice Execute the price change once the interval period ticks over, updating the long & short
     *         balances based on the change of the feed (upwards or downwards) and paying fees
     * @dev Can only be called by poolUpkeep; emits PriceChangeError if execution does not take place
     * @param _oldPrice Old price from the oracle
     * @param _newPrice New price from the oracle
     */
    function executePriceChange(int256 _oldPrice, int256 _newPrice) internal onlyUnpaused {
        // prevent a division by 0 in computing the price change
        // prevent negative pricing
        if (_oldPrice <= 0 || _newPrice <= 0) {
            emit PriceChangeError(_oldPrice, _newPrice);
        } else {
            uint256 _shortBalance = shortBalance;
            uint256 _longBalance = longBalance;
            PoolSwapLibrary.PriceChangeData memory priceChangeData = PoolSwapLibrary.PriceChangeData(
                _oldPrice,
                _newPrice,
                _longBalance,
                _shortBalance,
                leverageAmount,
                fee
            );
            (uint256 newLongBalance, uint256 newShortBalance, uint256 totalFeeAmount) = PoolSwapLibrary
                .calculatePriceChange(priceChangeData);

            emit PoolRebalance(
                int256(newShortBalance) - int256(_shortBalance),
                int256(newLongBalance) - int256(_longBalance)
            );
            // Update pool balances
            longBalance = newLongBalance;
            shortBalance = newShortBalance;
            // Pay the fee
            IERC20(quoteToken).safeTransfer(feeAddress, totalFeeAmount);
        }
    }

    /**
     * @notice Sets the long and short balances of the pools
     * @dev Can only be called by & used by the pool committer
     * @param _longBalance New balance of the long pool
     * @param _shortBalance New balancee of the short pool
     */
    function setNewPoolBalances(uint256 _longBalance, uint256 _shortBalance)
        external
        override
        onlyPoolCommitter
        onlyUnpaused
    {
        longBalance = _longBalance;
        shortBalance = _shortBalance;
    }

    /**
     * @notice Mint tokens to a user
     * @dev Can only be called by & used by the pool committer
     * @param token Index of token
     * @param amount Amount of tokens to mint
     * @param minter Address of user/minter
     */
    function mintTokens(
        uint256 token,
        uint256 amount,
        address minter
    ) external override onlyPoolCommitter onlyUnpaused {
        require(minter != address(0), "Minter address cannot be 0 address");
        require(token == 0 || token == 1, "Pool: token out of range");
        require(IPoolToken(tokens[token]).mint(amount, minter), "Mint failed");
    }

    /**
     * @notice Burn tokens by a user
     * @dev Can only be called by & used by the pool committer
     * @param token Index of token
     * @param amount Amount of tokens to burn
     * @param burner Address of user/burner
     */
    function burnTokens(
        uint256 token,
        uint256 amount,
        address burner
    ) external override onlyPoolCommitter onlyUnpaused {
        require(burner != address(0), "Burner address cannot be 0 address");
        require(token == 0 || token == 1, "Pool: token out of range");
        require(IPoolToken(tokens[token]).burn(amount, burner), "Burn failed");
    }

    /**
     * @return true if the price was last updated more than updateInterval seconds ago
     */
    function intervalPassed() public view override returns (bool) {
        return block.timestamp >= lastPriceTimestamp + updateInterval;
    }

    /**
     * @notice Updates the fee address of the pool
     * @param account New address of the fee address/receiver
     */
    function updateFeeAddress(address account) external override onlyGov onlyUnpaused {
        require(account != address(0), "Account cannot be 0 address");
        address oldFeeAddress = feeAddress;
        feeAddress = account;
        emit FeeAddressUpdated(oldFeeAddress, feeAddress);
    }

    /**
     * @notice Updates the keeper contract of the pool
     * @param _keeper New address of the keeper contract
     */
    function setKeeper(address _keeper) external override onlyGov onlyUnpaused {
        require(_keeper != address(0), "Keeper address cannot be 0 address");
        address oldKeeper = keeper;
        keeper = _keeper;
        emit KeeperAddressChanged(oldKeeper, keeper);
    }

    /**
     * @notice Starts to transfer governance of the pool. The new governance
     *          address must call `claimGovernance` in order for this to take
     *          effect. Until this occurs, the existing governance address
     *          remains in control of the pool.
     * @param _governance New address of the governance of the pool
     * @dev First step of the two-step governance transfer process
     * @dev Sets the governance transfer flag to true
     * @dev See `claimGovernance`
     */
    function transferGovernance(address _governance) external override onlyGov onlyUnpaused {
        require(_governance != address(0), "Governance address cannot be 0 address");
        provisionalGovernance = _governance;
        governanceTransferInProgress = true;
        emit ProvisionalGovernanceChanged(provisionalGovernance);
    }

    /**
     * @notice Completes transfer of governance by actually changing permissions
     *          over the pool.
     * @dev Second and final step of the two-step governance transfer process
     * @dev See `transferGovernance`
     * @dev Sets the governance transfer flag to false
     * @dev After a successful call to this function, the actual governance
     *      address and the provisional governance address MUST be equal.
     */
    function claimGovernance() external override onlyUnpaused {
        require(governanceTransferInProgress, "No governance change active");
        require(msg.sender == provisionalGovernance, "Not provisional governor");
        address oldGovernance = governance; /* for later event emission */
        governance = provisionalGovernance;
        governanceTransferInProgress = false;
        emit GovernanceAddressChanged(oldGovernance, governance);
    }

    /**
     * @return _latestPrice The oracle price
     * @return _data The oracleWrapper's metadata. Implementations can choose what data to return here
     * @return _lastPriceTimestamp The timestamp of the last upkeep
     * @return _updateInterval The update frequency for this pool
     * @dev To save gas so PoolKeeper does not have to make three external calls
     */
    function getUpkeepInformation()
        external
        view
        override
        returns (
            int256 _latestPrice,
            bytes memory _data,
            uint256 _lastPriceTimestamp,
            uint256 _updateInterval
        )
    {
        (_latestPrice, _data) = IOracleWrapper(oracleWrapper).getPriceAndMetadata();
        return (_latestPrice, _data, lastPriceTimestamp, updateInterval);
    }

    /**
     * @return The price of the pool's feed oracle
     */
    function getOraclePrice() external view override returns (int256) {
        return IOracleWrapper(oracleWrapper).getPrice();
    }

    function poolTokens() external view override returns (address[2] memory) {
        return tokens;
    }

    function balances() external view override returns (uint256 _shortBalance, uint256 _longBalance) {
        return (shortBalance, longBalance);
    }

    /**
     * @notice Withdraws all available quote asset from the pool
     * @dev Pool must not be paused
     * @dev ERC20 transfer
     */
    function withdrawQuote() external onlyGov {
        require(paused, "Pool is live");
        IERC20 quoteERC = IERC20(quoteToken);
        uint256 balance = quoteERC.balanceOf(address(this));
        IERC20(quoteToken).safeTransfer(msg.sender, balance);
    }

    /**
     * @notice Pauses the pool
     * @dev Prevents all state updates until unpaused
     */
    function pause() external onlyGov {
        paused = true;
        emit Paused();
    }

    /**
     * @notice Unpauses the pool
     * @dev Prevents all state updates until unpaused
     */
    function unpause() external onlyGov {
        paused = false;
        emit Unpaused();
    }

    // #### Modifiers
    modifier onlyUnpaused() {
        require(!paused, "Pool is paused");
        _;
    }

    modifier onlyKeeper() {
        require(msg.sender == keeper, "msg.sender not keeper");
        _;
    }

    modifier onlyPoolCommitter() {
        require(msg.sender == poolCommitter, "msg.sender not poolCommitter");
        _;
    }

    modifier onlyFeeReceiver() {
        require(msg.sender == feeAddress, "msg.sender not feeReceiver");
        _;
    }

    modifier onlyGov() {
        require(msg.sender == governance, "msg.sender not governance");
        _;
    }
}

File 8 of 27 : PoolToken.sol
//SPDX-License-Identifier: CC-BY-NC-ND-4.0
pragma solidity 0.8.7;

import "../vendors/ERC20_Cloneable.sol";
import "../interfaces/IPoolToken.sol";

/// @title The pool token; used for ownership/shares of the underlying tokens of the long/short pool
/// @dev ERC_20_Cloneable contains onlyOwner code implemented for use with the cloneable setup
contract PoolToken is ERC20_Cloneable, IPoolToken {
    // #### Global state

    // #### Functions

    constructor(uint8 _decimals) ERC20_Cloneable("BASE_TOKEN", "BASE", _decimals) {}

    /**
     * @notice Mints pool tokens
     * @param amount Pool tokens to burn
     * @param account Account to burn pool tokens to
     * @return Whether the mint was successful
     */
    function mint(uint256 amount, address account) external override onlyOwner returns (bool) {
        _mint(account, amount);
        return true;
    }

    /**
     * @notice Burns pool tokens
     * @param amount Pool tokens to burn
     * @param account Account to burn pool tokens from
     * @return Whether the burn was successful
     */
    function burn(uint256 amount, address account) external override onlyOwner returns (bool) {
        _burn(account, amount);
        return true;
    }
}

File 9 of 27 : PoolKeeper.sol
//SPDX-License-Identifier: CC-BY-NC-ND-4.0
pragma solidity 0.8.7;

import "../interfaces/IPoolKeeper.sol";
import "../interfaces/IOracleWrapper.sol";
import "../interfaces/IPoolFactory.sol";
import "../interfaces/ILeveragedPool.sol";
import "../interfaces/IERC20DecimalsWrapper.sol";
import "../interfaces/IERC20DecimalsWrapper.sol";
import "./PoolSwapLibrary.sol";

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/proxy/Clones.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "abdk-libraries-solidity/ABDKMathQuad.sol";
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV2V3Interface.sol";

/// @title The manager contract for multiple markets and the pools in them
contract PoolKeeper is IPoolKeeper, Ownable {
    /* Constants */
    uint256 public constant BASE_TIP = 5; // 5% base tip
    uint256 public constant TIP_DELTA_PER_BLOCK = 5; // 5% increase per block
    uint256 public constant BLOCK_TIME = 13; /* in seconds */
    uint256 public constant MAX_DECIMALS = 18;

    // #### Global variables
    /**
     * @notice Format: Pool address => last executionPrice
     */
    mapping(address => int256) public executionPrice;

    IPoolFactory public factory;
    bytes16 constant fixedPoint = 0x403abc16d674ec800000000000000000; // 1 ether

    uint256 public gasPrice = 10 gwei;

    // #### Functions
    constructor(address _factory) {
        require(_factory != address(0), "Factory cannot be 0 address");
        factory = IPoolFactory(_factory);
    }

    /**
     * @notice When a pool is created, this function is called by the factory to initiate price trackings
     * @param _poolAddress The address of the newly-created pools
     */
    function newPool(address _poolAddress) external override onlyFactory {
        address oracleWrapper = ILeveragedPool(_poolAddress).oracleWrapper();
        int256 firstPrice = IOracleWrapper(oracleWrapper).getPrice();
        require(firstPrice > 0, "First price is non-positive");
        int256 startingPrice = ABDKMathQuad.toInt(ABDKMathQuad.mul(ABDKMathQuad.fromInt(firstPrice), fixedPoint));
        emit PoolAdded(_poolAddress, firstPrice);
        executionPrice[_poolAddress] = startingPrice;
    }

    // Keeper network
    /**
     * @notice Check if upkeep is required
     * @param _pool The address of the pool to upkeep
     * @return upkeepNeeded Whether or not upkeep is needed for this single pool
     */
    function checkUpkeepSinglePool(address _pool) public view override returns (bool) {
        if (!factory.isValidPool(_pool)) {
            return false;
        }

        // The update interval has passed
        return ILeveragedPool(_pool).intervalPassed();
    }

    /**
     * @notice Checks multiple pools if any of them need updating
     * @param _pools The array of pools to check
     * @return upkeepNeeded Whether or not at least one pool needs upkeeping
     */
    function checkUpkeepMultiplePools(address[] calldata _pools) external view override returns (bool) {
        for (uint256 i = 0; i < _pools.length; i++) {
            if (checkUpkeepSinglePool(_pools[i])) {
                // One has been found that requires upkeeping
                return true;
            }
        }
        return false;
    }

    /**
     * @notice Called by keepers to perform an update on a single pool
     * @param _pool The pool code to perform the update for
     */
    function performUpkeepSinglePool(address _pool) public override {
        uint256 startGas = gasleft();

        // validate the pool, check that the interval time has passed
        if (!checkUpkeepSinglePool(_pool)) {
            return;
        }
        ILeveragedPool pool = ILeveragedPool(_pool);
        (int256 latestPrice, bytes memory data, uint256 savedPreviousUpdatedTimestamp, uint256 updateInterval) = pool
            .getUpkeepInformation();

        // Start a new round
        // Get price in WAD format
        int256 lastExecutionPrice = executionPrice[_pool];
        executionPrice[_pool] = latestPrice;

        // This allows us to still batch multiple calls to executePriceChange, even if some are invalid
        // Without reverting the entire transaction
        try pool.poolUpkeep(lastExecutionPrice, latestPrice) {
            // If poolUpkeep is successful, refund the keeper for their gas costs
            uint256 gasSpent = startGas - gasleft();

            payKeeper(_pool, gasPrice, gasSpent, savedPreviousUpdatedTimestamp, updateInterval);
            emit UpkeepSuccessful(_pool, data, lastExecutionPrice, latestPrice);
        } catch Error(string memory reason) {
            // If poolUpkeep fails for any other reason, emit event
            emit PoolUpkeepError(_pool, reason);
        }
    }

    /**
     * @notice Called by keepers to perform an update on multiple pools
     * @param pools pool codes to perform the update for
     */
    function performUpkeepMultiplePools(address[] calldata pools) external override {
        for (uint256 i = 0; i < pools.length; i++) {
            performUpkeepSinglePool(pools[i]);
        }
    }

    /**
     * @notice Pay keeper for upkeep
     * @param _pool Address of the given pool
     * @param _gasPrice Price of a single gas unit (in ETH)
     * @param _gasSpent Number of gas units spent
     * @param _savedPreviousUpdatedTimestamp Last timestamp when the pool's price execution happened
     * @param _updateInterval Pool interval of the given pool
     */
    function payKeeper(
        address _pool,
        uint256 _gasPrice,
        uint256 _gasSpent,
        uint256 _savedPreviousUpdatedTimestamp,
        uint256 _updateInterval
    ) internal {
        uint256 reward = keeperReward(_pool, _gasPrice, _gasSpent, _savedPreviousUpdatedTimestamp, _updateInterval);
        if (ILeveragedPool(_pool).payKeeperFromBalances(msg.sender, reward)) {
            emit KeeperPaid(_pool, msg.sender, reward);
        } else {
            // Usually occurs if pool just started and does not have any funds
            emit KeeperPaymentError(_pool, msg.sender, reward);
        }
    }

    /**
     * @notice Payment keeper receives for performing upkeep on a given pool
     * @param _pool Address of the given pool
     * @param _gasPrice Price of a single gas unit (in ETH)
     * @param _gasSpent Number of gas units spent
     * @param _savedPreviousUpdatedTimestamp Last timestamp when the pool's price execution happened
     * @param _poolInterval Pool interval of the given pool
     * @return Number of settlement tokens to give to the keeper for work performed
     */
    function keeperReward(
        address _pool,
        uint256 _gasPrice,
        uint256 _gasSpent,
        uint256 _savedPreviousUpdatedTimestamp,
        uint256 _poolInterval
    ) public view returns (uint256) {
        // keeper gas cost in wei. WAD formatted
        uint256 _keeperGas = keeperGas(_pool, _gasPrice, _gasSpent);

        // tip percent in wad units
        bytes16 _tipPercent = ABDKMathQuad.fromUInt(keeperTip(_savedPreviousUpdatedTimestamp, _poolInterval));

        // amount of settlement tokens to give to the keeper
        _tipPercent = ABDKMathQuad.div(_tipPercent, ABDKMathQuad.fromUInt(100));
        int256 wadRewardValue = ABDKMathQuad.toInt(
            ABDKMathQuad.add(
                ABDKMathQuad.fromUInt(_keeperGas),
                ABDKMathQuad.div((ABDKMathQuad.mul(ABDKMathQuad.fromUInt(_keeperGas), _tipPercent)), fixedPoint)
            )
        );
        uint256 decimals = IERC20DecimalsWrapper(ILeveragedPool(_pool).quoteToken()).decimals();
        uint256 deWadifiedReward = PoolSwapLibrary.fromWad(uint256(wadRewardValue), decimals);
        // _keeperGas + _keeperGas * percentTip
        return deWadifiedReward;
    }

    /**
     * @notice Compensation a keeper will receive for their gas expenditure
     * @param _pool Address of the given pool
     * @param _gasPrice Price of a single gas unit (in ETH)
     * @param _gasSpent Number of gas units spent
     * @return Keeper's gas compensation
     */
    function keeperGas(
        address _pool,
        uint256 _gasPrice,
        uint256 _gasSpent
    ) public view returns (uint256) {
        int256 settlementTokenPrice = IOracleWrapper(ILeveragedPool(_pool).settlementEthOracle()).getPrice();

        if (settlementTokenPrice <= 0) {
            return 0;
        } else {
            /* safe due to explicit bounds check above */
            /* (wei * Settlement / ETH) / fixed point (10^18) = amount in settlement */
            bytes16 _weiSpent = ABDKMathQuad.fromUInt(_gasPrice * _gasSpent);
            bytes16 _settlementTokenPrice = ABDKMathQuad.fromUInt(uint256(settlementTokenPrice));
            return
                ABDKMathQuad.toUInt(ABDKMathQuad.div(ABDKMathQuad.mul(_weiSpent, _settlementTokenPrice), fixedPoint));
        }
    }

    /**
     * @notice Tip a keeper will receive for successfully updating the specified pool
     * @param _savedPreviousUpdatedTimestamp Last timestamp when the pool's price execution happened
     * @param _poolInterval Pool interval of the given pool
     * @return Percent of the `keeperGas` cost to add to payment, as a percent
     */
    function keeperTip(uint256 _savedPreviousUpdatedTimestamp, uint256 _poolInterval) public view returns (uint256) {
        /* the number of blocks that have elapsed since the given pool's updateInterval passed */
        uint256 elapsedBlocksNumerator = (block.timestamp - (_savedPreviousUpdatedTimestamp + _poolInterval));

        uint256 keeperTip = BASE_TIP + (TIP_DELTA_PER_BLOCK * elapsedBlocksNumerator) / BLOCK_TIME;

        // In case of network outages or otherwise, we want to cap the tip so that the keeper cost isn't unbounded
        if (keeperTip > 100) {
            return 100;
        } else {
            return keeperTip;
        }
    }

    function setFactory(address _factory) external override onlyOwner {
        factory = IPoolFactory(_factory);
    }

    /**
     * @notice Sets the gas price to be used in compensating keepers for successful upkeep
     * @param _price Price (in ETH) per unit gas
     * @dev Only owner
     */
    function setGasPrice(uint256 _price) external onlyOwner {
        gasPrice = _price;
    }

    modifier onlyFactory() {
        require(msg.sender == address(factory), "Caller not factory");
        _;
    }
}

File 10 of 27 : Clones.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for
 * deploying minimal proxy contracts, also known as "clones".
 *
 * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
 * > a minimal bytecode implementation that delegates all calls to a known, fixed address.
 *
 * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
 * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
 * deterministic method.
 *
 * _Available since v3.4._
 */
library Clones {
    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
     *
     * This function uses the create opcode, which should never revert.
     */
    function clone(address implementation) internal returns (address instance) {
        assembly {
            let ptr := mload(0x40)
            mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
            mstore(add(ptr, 0x14), shl(0x60, implementation))
            mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
            instance := create(0, ptr, 0x37)
        }
        require(instance != address(0), "ERC1167: create failed");
    }

    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
     *
     * This function uses the create2 opcode and a `salt` to deterministically deploy
     * the clone. Using the same `implementation` and `salt` multiple time will revert, since
     * the clones cannot be deployed twice at the same address.
     */
    function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
        assembly {
            let ptr := mload(0x40)
            mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
            mstore(add(ptr, 0x14), shl(0x60, implementation))
            mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
            instance := create2(0, ptr, 0x37, salt)
        }
        require(instance != address(0), "ERC1167: create2 failed");
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
     */
    function predictDeterministicAddress(
        address implementation,
        bytes32 salt,
        address deployer
    ) internal pure returns (address predicted) {
        assembly {
            let ptr := mload(0x40)
            mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
            mstore(add(ptr, 0x14), shl(0x60, implementation))
            mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000)
            mstore(add(ptr, 0x38), shl(0x60, deployer))
            mstore(add(ptr, 0x4c), salt)
            mstore(add(ptr, 0x6c), keccak256(ptr, 0x37))
            predicted := keccak256(add(ptr, 0x37), 0x55)
        }
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
     */
    function predictDeterministicAddress(address implementation, bytes32 salt)
        internal
        view
        returns (address predicted)
    {
        return predictDeterministicAddress(implementation, salt, address(this));
    }
}

File 11 of 27 : Ownable.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../utils/Context.sol";

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

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _setOwner(_msgSender());
    }

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

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

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

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

    function _setOwner(address newOwner) private {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

File 12 of 27 : IPoolToken.sol
//SPDX-License-Identifier: CC-BY-NC-ND-4.0
pragma solidity 0.8.7;

/// @title Interface for the pool tokens
interface IPoolToken {
    function mint(uint256 amount, address account) external returns (bool);

    function burn(uint256 amount, address account) external returns (bool);
}

File 13 of 27 : Initializable.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 */
abstract contract Initializable {
    /**
     * @dev Indicates that the contract has been initialized.
     */
    bool private _initialized;

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

    /**
     * @dev Modifier to protect an initializer function from being invoked twice.
     */
    modifier initializer() {
        require(_initializing || !_initialized, "Initializable: contract is already initialized");

        bool isTopLevelCall = !_initializing;
        if (isTopLevelCall) {
            _initializing = true;
            _initialized = true;
        }

        _;

        if (isTopLevelCall) {
            _initializing = false;
        }
    }
}

File 14 of 27 : IERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @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 `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, 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 `sender` to `recipient` 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 sender,
        address recipient,
        uint256 amount
    ) external returns (bool);

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

File 15 of 27 : SafeERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../IERC20.sol";
import "../../../utils/Address.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));
        }
    }

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

File 16 of 27 : PoolSwapLibrary.sol
//SPDX-License-Identifier: CC-BY-NC-ND-4.0
pragma solidity 0.8.7;

import "abdk-libraries-solidity/ABDKMathQuad.sol";

/// @title Library for various useful (mostly) mathematical functions
library PoolSwapLibrary {
    bytes16 public constant one = 0x3fff0000000000000000000000000000;
    bytes16 public constant zero = 0x00000000000000000000000000000000;

    /* ABDKMathQuad defines this but it's private */
    bytes16 private constant NEGATIVE_ZERO = 0x80000000000000000000000000000000;
    uint256 public constant MAX_DECIMALS = 18;

    uint256 public constant WAD_PRECISION = 10**18;

    struct PriceChangeData {
        int256 oldPrice;
        int256 newPrice;
        uint256 longBalance;
        uint256 shortBalance;
        bytes16 leverageAmount;
        bytes16 fee;
    }

    /**
     * @notice Calculates the ratio between two numbers
     * @dev Rounds any overflow towards 0. If either parameter is zero, the ratio is 0
     * @param _numerator The "parts per" side of the equation. If this is zero, the ratio is zero
     * @param _denominator The "per part" side of the equation. If this is zero, the ratio is zero
     * @return the ratio, as an ABDKMathQuad number (IEEE 754 quadruple precision floating point)
     */
    function getRatio(uint256 _numerator, uint256 _denominator) public pure returns (bytes16) {
        // Catch the divide by zero error.
        if (_denominator == 0) {
            return 0;
        }
        return ABDKMathQuad.div(ABDKMathQuad.fromUInt(_numerator), ABDKMathQuad.fromUInt(_denominator));
    }

    /**
     * @notice Gets the short and long balances after the keeper rewards have been paid out
     *         Keeper rewards are paid proportionally to the short and long pool
     * @dev Assumes shortBalance + longBalance >= reward
     * @param reward Amount of keeper reward
     * @param shortBalance Short balance of the pool
     * @param longBalance Long balance of the pool
     * @return shortBalanceAfterFees Short balance of the pool after the keeper reward has been paid
     * @return longBalanceAfterFees Long balance of the pool after the keeper reward has been paid
     */
    function getBalancesAfterFees(
        uint256 reward,
        uint256 shortBalance,
        uint256 longBalance
    ) external pure returns (uint256, uint256) {
        bytes16 ratioShort = getRatio(shortBalance, shortBalance + longBalance);

        uint256 shortFees = convertDecimalToUInt(multiplyDecimalByUInt(ratioShort, reward));

        uint256 shortBalanceAfterFees = shortBalance - shortFees;
        uint256 longBalanceAfterFees = longBalance - (reward - shortFees);

        // Return shortBalance and longBalance after rewards are paid out
        return (shortBalanceAfterFees, longBalanceAfterFees);
    }

    /**
     * @notice Compares two decimal numbers
     * @param x The first number to compare
     * @param y The second number to compare
     * @return -1 if x < y, 0 if x = y, or 1 if x > y
     */
    function compareDecimals(bytes16 x, bytes16 y) public pure returns (int8) {
        return ABDKMathQuad.cmp(x, y);
    }

    /**
     * @notice Converts an integer value to a compatible decimal value
     * @param amount The amount to convert
     * @return The amount as a IEEE754 quadruple precision number
     */
    function convertUIntToDecimal(uint256 amount) external pure returns (bytes16) {
        return ABDKMathQuad.fromUInt(amount);
    }

    /**
     * @notice Converts a raw decimal value to a more readable uint256 value
     * @param ratio The value to convert
     * @return The converted value
     */
    function convertDecimalToUInt(bytes16 ratio) public pure returns (uint256) {
        return ABDKMathQuad.toUInt(ratio);
    }

    /**
     * @notice Multiplies a decimal and an unsigned integer
     * @param a The first term
     * @param b The second term
     * @return The product of a*b as a decimal
     */
    function multiplyDecimalByUInt(bytes16 a, uint256 b) public pure returns (bytes16) {
        return ABDKMathQuad.mul(a, ABDKMathQuad.fromUInt(b));
    }

    /**
     * @notice Divides two integers
     * @param a The dividend
     * @param b The divisor
     * @return The quotient
     */
    function divInt(int256 a, int256 b) public pure returns (bytes16) {
        return ABDKMathQuad.div(ABDKMathQuad.fromInt(a), ABDKMathQuad.fromInt(b));
    }

    /**
     * @notice Calculates the loss multiplier to apply to the losing pool. Includes the power leverage
     * @param ratio The ratio of new price to old price
     * @param direction The direction of the change. -1 if it's decreased, 0 if it hasn't changed, and 1 if it's increased
     * @param leverage The amount of leverage to apply
     * @return The multiplier
     */
    function getLossMultiplier(
        bytes16 ratio,
        int8 direction,
        bytes16 leverage
    ) public pure returns (bytes16) {
        // If decreased:  2 ^ (leverage * log2[(1 * new/old) + [(0 * 1) / new/old]])
        //              = 2 ^ (leverage * log2[(new/old)])
        // If increased:  2 ^ (leverage * log2[(0 * new/old) + [(1 * 1) / new/old]])
        //              = 2 ^ (leverage * log2([1 / new/old]))
        //              = 2 ^ (leverage * log2([old/new]))
        return
            ABDKMathQuad.pow_2(
                ABDKMathQuad.mul(leverage, ABDKMathQuad.log_2(direction < 0 ? ratio : ABDKMathQuad.div(one, ratio)))
            );
    }

    /**
     * @notice Calculates the amount to take from the losing pool
     * @param lossMultiplier The multiplier to use
     * @param balance The balance of the losing pool
     */
    function getLossAmount(bytes16 lossMultiplier, uint256 balance) public pure returns (uint256) {
        return
            ABDKMathQuad.toUInt(
                ABDKMathQuad.mul(ABDKMathQuad.sub(one, lossMultiplier), ABDKMathQuad.fromUInt(balance))
            );
    }

    /**
     * @notice Calculates the effect of a price change. This involves calculating how many funds to transfer from the losing pool to the other.
     * @dev This function should be called by the LeveragedPool.
     * @param priceChange The struct containing necessary data to calculate price change
     */
    function calculatePriceChange(PriceChangeData memory priceChange)
        external
        pure
        returns (
            uint256,
            uint256,
            uint256
        )
    {
        uint256 shortBalance = priceChange.shortBalance;
        uint256 longBalance = priceChange.longBalance;
        bytes16 leverageAmount = priceChange.leverageAmount;
        int256 oldPrice = priceChange.oldPrice;
        int256 newPrice = priceChange.newPrice;
        bytes16 fee = priceChange.fee;

        // Calculate fees from long and short sides
        uint256 longFeeAmount = convertDecimalToUInt(multiplyDecimalByUInt(fee, longBalance)) /
            PoolSwapLibrary.WAD_PRECISION;
        uint256 shortFeeAmount = convertDecimalToUInt(multiplyDecimalByUInt(fee, shortBalance)) /
            PoolSwapLibrary.WAD_PRECISION;

        shortBalance = shortBalance - shortFeeAmount;
        longBalance = longBalance - longFeeAmount;
        uint256 totalFeeAmount = shortFeeAmount + longFeeAmount;

        // Use the ratio to determine if the price increased or decreased and therefore which direction
        // the funds should be transferred towards.

        bytes16 ratio = divInt(newPrice, oldPrice);
        int8 direction = compareDecimals(ratio, PoolSwapLibrary.one);
        // Take into account the leverage
        bytes16 lossMultiplier = getLossMultiplier(ratio, direction, leverageAmount);

        if (direction >= 0 && shortBalance > 0) {
            // Move funds from short to long pair
            uint256 lossAmount = getLossAmount(lossMultiplier, shortBalance);
            shortBalance = shortBalance - lossAmount;
            longBalance = longBalance + lossAmount;
        } else if (direction < 0 && longBalance > 0) {
            // Move funds from long to short pair
            uint256 lossAmount = getLossAmount(lossMultiplier, longBalance);
            shortBalance = shortBalance + lossAmount;
            longBalance = longBalance - lossAmount;
        }

        return (longBalance, shortBalance, totalFeeAmount);
    }

    /**
     * @notice Returns true if the given timestamp is BEFORE the frontRunningInterval starts,
     *         which is allowed for uncommitment.
     * @dev If you try to uncommit AFTER the frontRunningInterval, it should revert.
     * @param subjectTime The timestamp for which you want to calculate if it was beforeFrontRunningInterval
     * @param lastPriceTimestamp The timestamp of the last price update
     * @param updateInterval The interval between price updates
     * @param frontRunningInterval The window of time before a price udpate users can not uncommit or have their commit executed from
     */
    function isBeforeFrontRunningInterval(
        uint256 subjectTime,
        uint256 lastPriceTimestamp,
        uint256 updateInterval,
        uint256 frontRunningInterval
    ) external pure returns (bool) {
        return lastPriceTimestamp + updateInterval - frontRunningInterval > subjectTime;
    }

    /**
     * @notice Gets the number of settlement tokens to be withdrawn based on a pool token burn amount
     * @dev Calculates as `balance * amountIn / (tokenSupply + shadowBalance)
     * @param tokenSupply Total supply of pool tokens
     * @param amountIn Commitment amount of collateral tokens going into the pool
     * @param balance Balance of the pool (no. of underlying collateral tokens in pool)
     * @param shadowBalance Balance the shadow pool at time of mint
     * @return Number of settlement tokens to be withdrawn on a burn
     */
    function getWithdrawAmountOnBurn(
        uint256 tokenSupply,
        uint256 amountIn,
        uint256 balance,
        uint256 shadowBalance
    ) external pure returns (uint256) {
        require(amountIn > 0, "Invalid amount");

        // Catch the divide by zero error.
        if (balance == 0 || tokenSupply + shadowBalance == 0) {
            return amountIn;
        }
        bytes16 numerator = ABDKMathQuad.mul(ABDKMathQuad.fromUInt(balance), ABDKMathQuad.fromUInt(amountIn));
        return ABDKMathQuad.toUInt(ABDKMathQuad.div(numerator, ABDKMathQuad.fromUInt(tokenSupply + shadowBalance)));
    }

    /**
     * @notice Gets the number of pool tokens to be minted based on existing tokens
     * @dev Calculated as (tokenSupply + shadowBalance) * amountIn / balance
     * @param tokenSupply Total supply of pool tokens
     * @param amountIn Commitment amount of collateral tokens going into the pool
     * @param balance Balance of the pool (no. of underlying collateral tokens in pool)
     * @param shadowBalance Balance the shadow pool at time of mint
     * @return Number of pool tokens to be minted
     */
    function getMintAmount(
        uint256 tokenSupply,
        uint256 amountIn,
        uint256 balance,
        uint256 shadowBalance
    ) external pure returns (uint256) {
        require(amountIn > 0, "Invalid amount");

        // Catch the divide by zero error.
        if (balance == 0 || tokenSupply + shadowBalance == 0) {
            return amountIn;
        }

        bytes16 numerator = ABDKMathQuad.mul(
            ABDKMathQuad.fromUInt(tokenSupply + shadowBalance),
            ABDKMathQuad.fromUInt(amountIn)
        );
        return ABDKMathQuad.toUInt(ABDKMathQuad.div(numerator, ABDKMathQuad.fromUInt(balance)));
    }

    /**
     * @notice Converts from a WAD to normal value
     * @return Converted non-WAD value
     */
    function fromWad(uint256 _wadValue, uint256 _decimals) external pure returns (uint256) {
        uint256 scaler = 10**(MAX_DECIMALS - _decimals);
        return _wadValue / scaler;
    }
}

File 17 of 27 : IOracleWrapper.sol
//SPDX-License-Identifier: CC-BY-NC-ND-4.0
pragma solidity 0.8.7;

/// @title The oracle wrapper contract interface
interface IOracleWrapper {
    function oracle() external view returns (address);

    // #### Functions
    /**
     * @notice Sets the oracle for a given market
     * @dev Should be secured, ideally only allowing the PoolKeeper to access
     * @param _oracle The oracle to set for the market
     */
    function setOracle(address _oracle) external;

    /**
     * @notice Returns the current price for the asset in question
     * @return The latest price
     */
    function getPrice() external view returns (int256);

    /**
     * @return _price The latest round data price
     * @return _data The metadata. Implementations can choose what data to return here
     */
    function getPriceAndMetadata() external view returns (int256 _price, bytes memory _data);

    /**
     * @notice Converts from a WAD to normal value
     * @return Converted non-WAD value
     */
    function fromWad(int256 wad) external view returns (int256);
}

File 18 of 27 : Address.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @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
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        assembly {
            size := extcodesize(account)
        }
        return size > 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);
    }

    function _verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) private 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

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

File 19 of 27 : ABDKMathQuad.sol
// SPDX-License-Identifier: BSD-4-Clause
/*
 * ABDK Math Quad Smart Contract Library.  Copyright © 2019 by ABDK Consulting.
 * Author: Mikhail Vladimirov <[email protected]>
 */
pragma solidity ^0.8.0;

/**
 * Smart contract library of mathematical functions operating with IEEE 754
 * quadruple-precision binary floating-point numbers (quadruple precision
 * numbers).  As long as quadruple precision numbers are 16-bytes long, they are
 * represented by bytes16 type.
 */
library ABDKMathQuad {
  /*
   * 0.
   */
  bytes16 private constant POSITIVE_ZERO = 0x00000000000000000000000000000000;

  /*
   * -0.
   */
  bytes16 private constant NEGATIVE_ZERO = 0x80000000000000000000000000000000;

  /*
   * +Infinity.
   */
  bytes16 private constant POSITIVE_INFINITY = 0x7FFF0000000000000000000000000000;

  /*
   * -Infinity.
   */
  bytes16 private constant NEGATIVE_INFINITY = 0xFFFF0000000000000000000000000000;

  /*
   * Canonical NaN value.
   */
  bytes16 private constant NaN = 0x7FFF8000000000000000000000000000;

  /**
   * Convert signed 256-bit integer number into quadruple precision number.
   *
   * @param x signed 256-bit integer number
   * @return quadruple precision number
   */
  function fromInt (int256 x) internal pure returns (bytes16) {
    unchecked {
      if (x == 0) return bytes16 (0);
      else {
        // We rely on overflow behavior here
        uint256 result = uint256 (x > 0 ? x : -x);

        uint256 msb = mostSignificantBit (result);
        if (msb < 112) result <<= 112 - msb;
        else if (msb > 112) result >>= msb - 112;

        result = result & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF | 16383 + msb << 112;
        if (x < 0) result |= 0x80000000000000000000000000000000;

        return bytes16 (uint128 (result));
      }
    }
  }

  /**
   * Convert quadruple precision number into signed 256-bit integer number
   * rounding towards zero.  Revert on overflow.
   *
   * @param x quadruple precision number
   * @return signed 256-bit integer number
   */
  function toInt (bytes16 x) internal pure returns (int256) {
    unchecked {
      uint256 exponent = uint128 (x) >> 112 & 0x7FFF;

      require (exponent <= 16638); // Overflow
      if (exponent < 16383) return 0; // Underflow

      uint256 result = uint256 (uint128 (x)) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF |
        0x10000000000000000000000000000;

      if (exponent < 16495) result >>= 16495 - exponent;
      else if (exponent > 16495) result <<= exponent - 16495;

      if (uint128 (x) >= 0x80000000000000000000000000000000) { // Negative
        require (result <= 0x8000000000000000000000000000000000000000000000000000000000000000);
        return -int256 (result); // We rely on overflow behavior here
      } else {
        require (result <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
        return int256 (result);
      }
    }
  }

  /**
   * Convert unsigned 256-bit integer number into quadruple precision number.
   *
   * @param x unsigned 256-bit integer number
   * @return quadruple precision number
   */
  function fromUInt (uint256 x) internal pure returns (bytes16) {
    unchecked {
      if (x == 0) return bytes16 (0);
      else {
        uint256 result = x;

        uint256 msb = mostSignificantBit (result);
        if (msb < 112) result <<= 112 - msb;
        else if (msb > 112) result >>= msb - 112;

        result = result & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF | 16383 + msb << 112;

        return bytes16 (uint128 (result));
      }
    }
  }

  /**
   * Convert quadruple precision number into unsigned 256-bit integer number
   * rounding towards zero.  Revert on underflow.  Note, that negative floating
   * point numbers in range (-1.0 .. 0.0) may be converted to unsigned integer
   * without error, because they are rounded to zero.
   *
   * @param x quadruple precision number
   * @return unsigned 256-bit integer number
   */
  function toUInt (bytes16 x) internal pure returns (uint256) {
    unchecked {
      uint256 exponent = uint128 (x) >> 112 & 0x7FFF;

      if (exponent < 16383) return 0; // Underflow

      require (uint128 (x) < 0x80000000000000000000000000000000); // Negative

      require (exponent <= 16638); // Overflow
      uint256 result = uint256 (uint128 (x)) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF |
        0x10000000000000000000000000000;

      if (exponent < 16495) result >>= 16495 - exponent;
      else if (exponent > 16495) result <<= exponent - 16495;

      return result;
    }
  }

  /**
   * Convert signed 128.128 bit fixed point number into quadruple precision
   * number.
   *
   * @param x signed 128.128 bit fixed point number
   * @return quadruple precision number
   */
  function from128x128 (int256 x) internal pure returns (bytes16) {
    unchecked {
      if (x == 0) return bytes16 (0);
      else {
        // We rely on overflow behavior here
        uint256 result = uint256 (x > 0 ? x : -x);

        uint256 msb = mostSignificantBit (result);
        if (msb < 112) result <<= 112 - msb;
        else if (msb > 112) result >>= msb - 112;

        result = result & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF | 16255 + msb << 112;
        if (x < 0) result |= 0x80000000000000000000000000000000;

        return bytes16 (uint128 (result));
      }
    }
  }

  /**
   * Convert quadruple precision number into signed 128.128 bit fixed point
   * number.  Revert on overflow.
   *
   * @param x quadruple precision number
   * @return signed 128.128 bit fixed point number
   */
  function to128x128 (bytes16 x) internal pure returns (int256) {
    unchecked {
      uint256 exponent = uint128 (x) >> 112 & 0x7FFF;

      require (exponent <= 16510); // Overflow
      if (exponent < 16255) return 0; // Underflow

      uint256 result = uint256 (uint128 (x)) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF |
        0x10000000000000000000000000000;

      if (exponent < 16367) result >>= 16367 - exponent;
      else if (exponent > 16367) result <<= exponent - 16367;

      if (uint128 (x) >= 0x80000000000000000000000000000000) { // Negative
        require (result <= 0x8000000000000000000000000000000000000000000000000000000000000000);
        return -int256 (result); // We rely on overflow behavior here
      } else {
        require (result <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
        return int256 (result);
      }
    }
  }

  /**
   * Convert signed 64.64 bit fixed point number into quadruple precision
   * number.
   *
   * @param x signed 64.64 bit fixed point number
   * @return quadruple precision number
   */
  function from64x64 (int128 x) internal pure returns (bytes16) {
    unchecked {
      if (x == 0) return bytes16 (0);
      else {
        // We rely on overflow behavior here
        uint256 result = uint128 (x > 0 ? x : -x);

        uint256 msb = mostSignificantBit (result);
        if (msb < 112) result <<= 112 - msb;
        else if (msb > 112) result >>= msb - 112;

        result = result & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF | 16319 + msb << 112;
        if (x < 0) result |= 0x80000000000000000000000000000000;

        return bytes16 (uint128 (result));
      }
    }
  }

  /**
   * Convert quadruple precision number into signed 64.64 bit fixed point
   * number.  Revert on overflow.
   *
   * @param x quadruple precision number
   * @return signed 64.64 bit fixed point number
   */
  function to64x64 (bytes16 x) internal pure returns (int128) {
    unchecked {
      uint256 exponent = uint128 (x) >> 112 & 0x7FFF;

      require (exponent <= 16446); // Overflow
      if (exponent < 16319) return 0; // Underflow

      uint256 result = uint256 (uint128 (x)) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF |
        0x10000000000000000000000000000;

      if (exponent < 16431) result >>= 16431 - exponent;
      else if (exponent > 16431) result <<= exponent - 16431;

      if (uint128 (x) >= 0x80000000000000000000000000000000) { // Negative
        require (result <= 0x80000000000000000000000000000000);
        return -int128 (int256 (result)); // We rely on overflow behavior here
      } else {
        require (result <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
        return int128 (int256 (result));
      }
    }
  }

  /**
   * Convert octuple precision number into quadruple precision number.
   *
   * @param x octuple precision number
   * @return quadruple precision number
   */
  function fromOctuple (bytes32 x) internal pure returns (bytes16) {
    unchecked {
      bool negative = x & 0x8000000000000000000000000000000000000000000000000000000000000000 > 0;

      uint256 exponent = uint256 (x) >> 236 & 0x7FFFF;
      uint256 significand = uint256 (x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;

      if (exponent == 0x7FFFF) {
        if (significand > 0) return NaN;
        else return negative ? NEGATIVE_INFINITY : POSITIVE_INFINITY;
      }

      if (exponent > 278526)
        return negative ? NEGATIVE_INFINITY : POSITIVE_INFINITY;
      else if (exponent < 245649)
        return negative ? NEGATIVE_ZERO : POSITIVE_ZERO;
      else if (exponent < 245761) {
        significand = (significand | 0x100000000000000000000000000000000000000000000000000000000000) >> 245885 - exponent;
        exponent = 0;
      } else {
        significand >>= 124;
        exponent -= 245760;
      }

      uint128 result = uint128 (significand | exponent << 112);
      if (negative) result |= 0x80000000000000000000000000000000;

      return bytes16 (result);
    }
  }

  /**
   * Convert quadruple precision number into octuple precision number.
   *
   * @param x quadruple precision number
   * @return octuple precision number
   */
  function toOctuple (bytes16 x) internal pure returns (bytes32) {
    unchecked {
      uint256 exponent = uint128 (x) >> 112 & 0x7FFF;

      uint256 result = uint128 (x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;

      if (exponent == 0x7FFF) exponent = 0x7FFFF; // Infinity or NaN
      else if (exponent == 0) {
        if (result > 0) {
          uint256 msb = mostSignificantBit (result);
          result = result << 236 - msb & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
          exponent = 245649 + msb;
        }
      } else {
        result <<= 124;
        exponent += 245760;
      }

      result |= exponent << 236;
      if (uint128 (x) >= 0x80000000000000000000000000000000)
        result |= 0x8000000000000000000000000000000000000000000000000000000000000000;

      return bytes32 (result);
    }
  }

  /**
   * Convert double precision number into quadruple precision number.
   *
   * @param x double precision number
   * @return quadruple precision number
   */
  function fromDouble (bytes8 x) internal pure returns (bytes16) {
    unchecked {
      uint256 exponent = uint64 (x) >> 52 & 0x7FF;

      uint256 result = uint64 (x) & 0xFFFFFFFFFFFFF;

      if (exponent == 0x7FF) exponent = 0x7FFF; // Infinity or NaN
      else if (exponent == 0) {
        if (result > 0) {
          uint256 msb = mostSignificantBit (result);
          result = result << 112 - msb & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
          exponent = 15309 + msb;
        }
      } else {
        result <<= 60;
        exponent += 15360;
      }

      result |= exponent << 112;
      if (x & 0x8000000000000000 > 0)
        result |= 0x80000000000000000000000000000000;

      return bytes16 (uint128 (result));
    }
  }

  /**
   * Convert quadruple precision number into double precision number.
   *
   * @param x quadruple precision number
   * @return double precision number
   */
  function toDouble (bytes16 x) internal pure returns (bytes8) {
    unchecked {
      bool negative = uint128 (x) >= 0x80000000000000000000000000000000;

      uint256 exponent = uint128 (x) >> 112 & 0x7FFF;
      uint256 significand = uint128 (x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;

      if (exponent == 0x7FFF) {
        if (significand > 0) return 0x7FF8000000000000; // NaN
        else return negative ?
            bytes8 (0xFFF0000000000000) : // -Infinity
            bytes8 (0x7FF0000000000000); // Infinity
      }

      if (exponent > 17406)
        return negative ?
            bytes8 (0xFFF0000000000000) : // -Infinity
            bytes8 (0x7FF0000000000000); // Infinity
      else if (exponent < 15309)
        return negative ?
            bytes8 (0x8000000000000000) : // -0
            bytes8 (0x0000000000000000); // 0
      else if (exponent < 15361) {
        significand = (significand | 0x10000000000000000000000000000) >> 15421 - exponent;
        exponent = 0;
      } else {
        significand >>= 60;
        exponent -= 15360;
      }

      uint64 result = uint64 (significand | exponent << 52);
      if (negative) result |= 0x8000000000000000;

      return bytes8 (result);
    }
  }

  /**
   * Test whether given quadruple precision number is NaN.
   *
   * @param x quadruple precision number
   * @return true if x is NaN, false otherwise
   */
  function isNaN (bytes16 x) internal pure returns (bool) {
    unchecked {
      return uint128 (x) & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF >
        0x7FFF0000000000000000000000000000;
    }
  }

  /**
   * Test whether given quadruple precision number is positive or negative
   * infinity.
   *
   * @param x quadruple precision number
   * @return true if x is positive or negative infinity, false otherwise
   */
  function isInfinity (bytes16 x) internal pure returns (bool) {
    unchecked {
      return uint128 (x) & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ==
        0x7FFF0000000000000000000000000000;
    }
  }

  /**
   * Calculate sign of x, i.e. -1 if x is negative, 0 if x if zero, and 1 if x
   * is positive.  Note that sign (-0) is zero.  Revert if x is NaN. 
   *
   * @param x quadruple precision number
   * @return sign of x
   */
  function sign (bytes16 x) internal pure returns (int8) {
    unchecked {
      uint128 absoluteX = uint128 (x) & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;

      require (absoluteX <= 0x7FFF0000000000000000000000000000); // Not NaN

      if (absoluteX == 0) return 0;
      else if (uint128 (x) >= 0x80000000000000000000000000000000) return -1;
      else return 1;
    }
  }

  /**
   * Calculate sign (x - y).  Revert if either argument is NaN, or both
   * arguments are infinities of the same sign. 
   *
   * @param x quadruple precision number
   * @param y quadruple precision number
   * @return sign (x - y)
   */
  function cmp (bytes16 x, bytes16 y) internal pure returns (int8) {
    unchecked {
      uint128 absoluteX = uint128 (x) & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;

      require (absoluteX <= 0x7FFF0000000000000000000000000000); // Not NaN

      uint128 absoluteY = uint128 (y) & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;

      require (absoluteY <= 0x7FFF0000000000000000000000000000); // Not NaN

      // Not infinities of the same sign
      require (x != y || absoluteX < 0x7FFF0000000000000000000000000000);

      if (x == y) return 0;
      else {
        bool negativeX = uint128 (x) >= 0x80000000000000000000000000000000;
        bool negativeY = uint128 (y) >= 0x80000000000000000000000000000000;

        if (negativeX) {
          if (negativeY) return absoluteX > absoluteY ? -1 : int8 (1);
          else return -1; 
        } else {
          if (negativeY) return 1;
          else return absoluteX > absoluteY ? int8 (1) : -1;
        }
      }
    }
  }

  /**
   * Test whether x equals y.  NaN, infinity, and -infinity are not equal to
   * anything. 
   *
   * @param x quadruple precision number
   * @param y quadruple precision number
   * @return true if x equals to y, false otherwise
   */
  function eq (bytes16 x, bytes16 y) internal pure returns (bool) {
    unchecked {
      if (x == y) {
        return uint128 (x) & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF <
          0x7FFF0000000000000000000000000000;
      } else return false;
    }
  }

  /**
   * Calculate x + y.  Special values behave in the following way:
   *
   * NaN + x = NaN for any x.
   * Infinity + x = Infinity for any finite x.
   * -Infinity + x = -Infinity for any finite x.
   * Infinity + Infinity = Infinity.
   * -Infinity + -Infinity = -Infinity.
   * Infinity + -Infinity = -Infinity + Infinity = NaN.
   *
   * @param x quadruple precision number
   * @param y quadruple precision number
   * @return quadruple precision number
   */
  function add (bytes16 x, bytes16 y) internal pure returns (bytes16) {
    unchecked {
      uint256 xExponent = uint128 (x) >> 112 & 0x7FFF;
      uint256 yExponent = uint128 (y) >> 112 & 0x7FFF;

      if (xExponent == 0x7FFF) {
        if (yExponent == 0x7FFF) { 
          if (x == y) return x;
          else return NaN;
        } else return x; 
      } else if (yExponent == 0x7FFF) return y;
      else {
        bool xSign = uint128 (x) >= 0x80000000000000000000000000000000;
        uint256 xSignifier = uint128 (x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
        if (xExponent == 0) xExponent = 1;
        else xSignifier |= 0x10000000000000000000000000000;

        bool ySign = uint128 (y) >= 0x80000000000000000000000000000000;
        uint256 ySignifier = uint128 (y) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
        if (yExponent == 0) yExponent = 1;
        else ySignifier |= 0x10000000000000000000000000000;

        if (xSignifier == 0) return y == NEGATIVE_ZERO ? POSITIVE_ZERO : y;
        else if (ySignifier == 0) return x == NEGATIVE_ZERO ? POSITIVE_ZERO : x;
        else {
          int256 delta = int256 (xExponent) - int256 (yExponent);
  
          if (xSign == ySign) {
            if (delta > 112) return x;
            else if (delta > 0) ySignifier >>= uint256 (delta);
            else if (delta < -112) return y;
            else if (delta < 0) {
              xSignifier >>= uint256 (-delta);
              xExponent = yExponent;
            }
  
            xSignifier += ySignifier;
  
            if (xSignifier >= 0x20000000000000000000000000000) {
              xSignifier >>= 1;
              xExponent += 1;
            }
  
            if (xExponent == 0x7FFF)
              return xSign ? NEGATIVE_INFINITY : POSITIVE_INFINITY;
            else {
              if (xSignifier < 0x10000000000000000000000000000) xExponent = 0;
              else xSignifier &= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
  
              return bytes16 (uint128 (
                  (xSign ? 0x80000000000000000000000000000000 : 0) |
                  (xExponent << 112) |
                  xSignifier)); 
            }
          } else {
            if (delta > 0) {
              xSignifier <<= 1;
              xExponent -= 1;
            } else if (delta < 0) {
              ySignifier <<= 1;
              xExponent = yExponent - 1;
            }

            if (delta > 112) ySignifier = 1;
            else if (delta > 1) ySignifier = (ySignifier - 1 >> uint256 (delta - 1)) + 1;
            else if (delta < -112) xSignifier = 1;
            else if (delta < -1) xSignifier = (xSignifier - 1 >> uint256 (-delta - 1)) + 1;

            if (xSignifier >= ySignifier) xSignifier -= ySignifier;
            else {
              xSignifier = ySignifier - xSignifier;
              xSign = ySign;
            }

            if (xSignifier == 0)
              return POSITIVE_ZERO;

            uint256 msb = mostSignificantBit (xSignifier);

            if (msb == 113) {
              xSignifier = xSignifier >> 1 & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
              xExponent += 1;
            } else if (msb < 112) {
              uint256 shift = 112 - msb;
              if (xExponent > shift) {
                xSignifier = xSignifier << shift & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
                xExponent -= shift;
              } else {
                xSignifier <<= xExponent - 1;
                xExponent = 0;
              }
            } else xSignifier &= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;

            if (xExponent == 0x7FFF)
              return xSign ? NEGATIVE_INFINITY : POSITIVE_INFINITY;
            else return bytes16 (uint128 (
                (xSign ? 0x80000000000000000000000000000000 : 0) |
                (xExponent << 112) |
                xSignifier));
          }
        }
      }
    }
  }

  /**
   * Calculate x - y.  Special values behave in the following way:
   *
   * NaN - x = NaN for any x.
   * Infinity - x = Infinity for any finite x.
   * -Infinity - x = -Infinity for any finite x.
   * Infinity - -Infinity = Infinity.
   * -Infinity - Infinity = -Infinity.
   * Infinity - Infinity = -Infinity - -Infinity = NaN.
   *
   * @param x quadruple precision number
   * @param y quadruple precision number
   * @return quadruple precision number
   */
  function sub (bytes16 x, bytes16 y) internal pure returns (bytes16) {
    unchecked {
      return add (x, y ^ 0x80000000000000000000000000000000);
    }
  }

  /**
   * Calculate x * y.  Special values behave in the following way:
   *
   * NaN * x = NaN for any x.
   * Infinity * x = Infinity for any finite positive x.
   * Infinity * x = -Infinity for any finite negative x.
   * -Infinity * x = -Infinity for any finite positive x.
   * -Infinity * x = Infinity for any finite negative x.
   * Infinity * 0 = NaN.
   * -Infinity * 0 = NaN.
   * Infinity * Infinity = Infinity.
   * Infinity * -Infinity = -Infinity.
   * -Infinity * Infinity = -Infinity.
   * -Infinity * -Infinity = Infinity.
   *
   * @param x quadruple precision number
   * @param y quadruple precision number
   * @return quadruple precision number
   */
  function mul (bytes16 x, bytes16 y) internal pure returns (bytes16) {
    unchecked {
      uint256 xExponent = uint128 (x) >> 112 & 0x7FFF;
      uint256 yExponent = uint128 (y) >> 112 & 0x7FFF;

      if (xExponent == 0x7FFF) {
        if (yExponent == 0x7FFF) {
          if (x == y) return x ^ y & 0x80000000000000000000000000000000;
          else if (x ^ y == 0x80000000000000000000000000000000) return x | y;
          else return NaN;
        } else {
          if (y & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0) return NaN;
          else return x ^ y & 0x80000000000000000000000000000000;
        }
      } else if (yExponent == 0x7FFF) {
          if (x & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0) return NaN;
          else return y ^ x & 0x80000000000000000000000000000000;
      } else {
        uint256 xSignifier = uint128 (x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
        if (xExponent == 0) xExponent = 1;
        else xSignifier |= 0x10000000000000000000000000000;

        uint256 ySignifier = uint128 (y) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
        if (yExponent == 0) yExponent = 1;
        else ySignifier |= 0x10000000000000000000000000000;

        xSignifier *= ySignifier;
        if (xSignifier == 0)
          return (x ^ y) & 0x80000000000000000000000000000000 > 0 ?
              NEGATIVE_ZERO : POSITIVE_ZERO;

        xExponent += yExponent;

        uint256 msb =
          xSignifier >= 0x200000000000000000000000000000000000000000000000000000000 ? 225 :
          xSignifier >= 0x100000000000000000000000000000000000000000000000000000000 ? 224 :
          mostSignificantBit (xSignifier);

        if (xExponent + msb < 16496) { // Underflow
          xExponent = 0;
          xSignifier = 0;
        } else if (xExponent + msb < 16608) { // Subnormal
          if (xExponent < 16496)
            xSignifier >>= 16496 - xExponent;
          else if (xExponent > 16496)
            xSignifier <<= xExponent - 16496;
          xExponent = 0;
        } else if (xExponent + msb > 49373) {
          xExponent = 0x7FFF;
          xSignifier = 0;
        } else {
          if (msb > 112)
            xSignifier >>= msb - 112;
          else if (msb < 112)
            xSignifier <<= 112 - msb;

          xSignifier &= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;

          xExponent = xExponent + msb - 16607;
        }

        return bytes16 (uint128 (uint128 ((x ^ y) & 0x80000000000000000000000000000000) |
            xExponent << 112 | xSignifier));
      }
    }
  }

  /**
   * Calculate x / y.  Special values behave in the following way:
   *
   * NaN / x = NaN for any x.
   * x / NaN = NaN for any x.
   * Infinity / x = Infinity for any finite non-negative x.
   * Infinity / x = -Infinity for any finite negative x including -0.
   * -Infinity / x = -Infinity for any finite non-negative x.
   * -Infinity / x = Infinity for any finite negative x including -0.
   * x / Infinity = 0 for any finite non-negative x.
   * x / -Infinity = -0 for any finite non-negative x.
   * x / Infinity = -0 for any finite non-negative x including -0.
   * x / -Infinity = 0 for any finite non-negative x including -0.
   * 
   * Infinity / Infinity = NaN.
   * Infinity / -Infinity = -NaN.
   * -Infinity / Infinity = -NaN.
   * -Infinity / -Infinity = NaN.
   *
   * Division by zero behaves in the following way:
   *
   * x / 0 = Infinity for any finite positive x.
   * x / -0 = -Infinity for any finite positive x.
   * x / 0 = -Infinity for any finite negative x.
   * x / -0 = Infinity for any finite negative x.
   * 0 / 0 = NaN.
   * 0 / -0 = NaN.
   * -0 / 0 = NaN.
   * -0 / -0 = NaN.
   *
   * @param x quadruple precision number
   * @param y quadruple precision number
   * @return quadruple precision number
   */
  function div (bytes16 x, bytes16 y) internal pure returns (bytes16) {
    unchecked {
      uint256 xExponent = uint128 (x) >> 112 & 0x7FFF;
      uint256 yExponent = uint128 (y) >> 112 & 0x7FFF;

      if (xExponent == 0x7FFF) {
        if (yExponent == 0x7FFF) return NaN;
        else return x ^ y & 0x80000000000000000000000000000000;
      } else if (yExponent == 0x7FFF) {
        if (y & 0x0000FFFFFFFFFFFFFFFFFFFFFFFFFFFF != 0) return NaN;
        else return POSITIVE_ZERO | (x ^ y) & 0x80000000000000000000000000000000;
      } else if (y & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0) {
        if (x & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0) return NaN;
        else return POSITIVE_INFINITY | (x ^ y) & 0x80000000000000000000000000000000;
      } else {
        uint256 ySignifier = uint128 (y) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
        if (yExponent == 0) yExponent = 1;
        else ySignifier |= 0x10000000000000000000000000000;

        uint256 xSignifier = uint128 (x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
        if (xExponent == 0) {
          if (xSignifier != 0) {
            uint shift = 226 - mostSignificantBit (xSignifier);

            xSignifier <<= shift;

            xExponent = 1;
            yExponent += shift - 114;
          }
        }
        else {
          xSignifier = (xSignifier | 0x10000000000000000000000000000) << 114;
        }

        xSignifier = xSignifier / ySignifier;
        if (xSignifier == 0)
          return (x ^ y) & 0x80000000000000000000000000000000 > 0 ?
              NEGATIVE_ZERO : POSITIVE_ZERO;

        assert (xSignifier >= 0x1000000000000000000000000000);

        uint256 msb =
          xSignifier >= 0x80000000000000000000000000000 ? mostSignificantBit (xSignifier) :
          xSignifier >= 0x40000000000000000000000000000 ? 114 :
          xSignifier >= 0x20000000000000000000000000000 ? 113 : 112;

        if (xExponent + msb > yExponent + 16497) { // Overflow
          xExponent = 0x7FFF;
          xSignifier = 0;
        } else if (xExponent + msb + 16380  < yExponent) { // Underflow
          xExponent = 0;
          xSignifier = 0;
        } else if (xExponent + msb + 16268  < yExponent) { // Subnormal
          if (xExponent + 16380 > yExponent)
            xSignifier <<= xExponent + 16380 - yExponent;
          else if (xExponent + 16380 < yExponent)
            xSignifier >>= yExponent - xExponent - 16380;

          xExponent = 0;
        } else { // Normal
          if (msb > 112)
            xSignifier >>= msb - 112;

          xSignifier &= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;

          xExponent = xExponent + msb + 16269 - yExponent;
        }

        return bytes16 (uint128 (uint128 ((x ^ y) & 0x80000000000000000000000000000000) |
            xExponent << 112 | xSignifier));
      }
    }
  }

  /**
   * Calculate -x.
   *
   * @param x quadruple precision number
   * @return quadruple precision number
   */
  function neg (bytes16 x) internal pure returns (bytes16) {
    unchecked {
      return x ^ 0x80000000000000000000000000000000;
    }
  }

  /**
   * Calculate |x|.
   *
   * @param x quadruple precision number
   * @return quadruple precision number
   */
  function abs (bytes16 x) internal pure returns (bytes16) {
    unchecked {
      return x & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
    }
  }

  /**
   * Calculate square root of x.  Return NaN on negative x excluding -0.
   *
   * @param x quadruple precision number
   * @return quadruple precision number
   */
  function sqrt (bytes16 x) internal pure returns (bytes16) {
    unchecked {
      if (uint128 (x) >  0x80000000000000000000000000000000) return NaN;
      else {
        uint256 xExponent = uint128 (x) >> 112 & 0x7FFF;
        if (xExponent == 0x7FFF) return x;
        else {
          uint256 xSignifier = uint128 (x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
          if (xExponent == 0) xExponent = 1;
          else xSignifier |= 0x10000000000000000000000000000;

          if (xSignifier == 0) return POSITIVE_ZERO;

          bool oddExponent = xExponent & 0x1 == 0;
          xExponent = xExponent + 16383 >> 1;

          if (oddExponent) {
            if (xSignifier >= 0x10000000000000000000000000000)
              xSignifier <<= 113;
            else {
              uint256 msb = mostSignificantBit (xSignifier);
              uint256 shift = (226 - msb) & 0xFE;
              xSignifier <<= shift;
              xExponent -= shift - 112 >> 1;
            }
          } else {
            if (xSignifier >= 0x10000000000000000000000000000)
              xSignifier <<= 112;
            else {
              uint256 msb = mostSignificantBit (xSignifier);
              uint256 shift = (225 - msb) & 0xFE;
              xSignifier <<= shift;
              xExponent -= shift - 112 >> 1;
            }
          }

          uint256 r = 0x10000000000000000000000000000;
          r = (r + xSignifier / r) >> 1;
          r = (r + xSignifier / r) >> 1;
          r = (r + xSignifier / r) >> 1;
          r = (r + xSignifier / r) >> 1;
          r = (r + xSignifier / r) >> 1;
          r = (r + xSignifier / r) >> 1;
          r = (r + xSignifier / r) >> 1; // Seven iterations should be enough
          uint256 r1 = xSignifier / r;
          if (r1 < r) r = r1;

          return bytes16 (uint128 (xExponent << 112 | r & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF));
        }
      }
    }
  }

  /**
   * Calculate binary logarithm of x.  Return NaN on negative x excluding -0.
   *
   * @param x quadruple precision number
   * @return quadruple precision number
   */
  function log_2 (bytes16 x) internal pure returns (bytes16) {
    unchecked {
      if (uint128 (x) > 0x80000000000000000000000000000000) return NaN;
      else if (x == 0x3FFF0000000000000000000000000000) return POSITIVE_ZERO; 
      else {
        uint256 xExponent = uint128 (x) >> 112 & 0x7FFF;
        if (xExponent == 0x7FFF) return x;
        else {
          uint256 xSignifier = uint128 (x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
          if (xExponent == 0) xExponent = 1;
          else xSignifier |= 0x10000000000000000000000000000;

          if (xSignifier == 0) return NEGATIVE_INFINITY;

          bool resultNegative;
          uint256 resultExponent = 16495;
          uint256 resultSignifier;

          if (xExponent >= 0x3FFF) {
            resultNegative = false;
            resultSignifier = xExponent - 0x3FFF;
            xSignifier <<= 15;
          } else {
            resultNegative = true;
            if (xSignifier >= 0x10000000000000000000000000000) {
              resultSignifier = 0x3FFE - xExponent;
              xSignifier <<= 15;
            } else {
              uint256 msb = mostSignificantBit (xSignifier);
              resultSignifier = 16493 - msb;
              xSignifier <<= 127 - msb;
            }
          }

          if (xSignifier == 0x80000000000000000000000000000000) {
            if (resultNegative) resultSignifier += 1;
            uint256 shift = 112 - mostSignificantBit (resultSignifier);
            resultSignifier <<= shift;
            resultExponent -= shift;
          } else {
            uint256 bb = resultNegative ? 1 : 0;
            while (resultSignifier < 0x10000000000000000000000000000) {
              resultSignifier <<= 1;
              resultExponent -= 1;
  
              xSignifier *= xSignifier;
              uint256 b = xSignifier >> 255;
              resultSignifier += b ^ bb;
              xSignifier >>= 127 + b;
            }
          }

          return bytes16 (uint128 ((resultNegative ? 0x80000000000000000000000000000000 : 0) |
              resultExponent << 112 | resultSignifier & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF));
        }
      }
    }
  }

  /**
   * Calculate natural logarithm of x.  Return NaN on negative x excluding -0.
   *
   * @param x quadruple precision number
   * @return quadruple precision number
   */
  function ln (bytes16 x) internal pure returns (bytes16) {
    unchecked {
      return mul (log_2 (x), 0x3FFE62E42FEFA39EF35793C7673007E5);
    }
  }

  /**
   * Calculate 2^x.
   *
   * @param x quadruple precision number
   * @return quadruple precision number
   */
  function pow_2 (bytes16 x) internal pure returns (bytes16) {
    unchecked {
      bool xNegative = uint128 (x) > 0x80000000000000000000000000000000;
      uint256 xExponent = uint128 (x) >> 112 & 0x7FFF;
      uint256 xSignifier = uint128 (x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;

      if (xExponent == 0x7FFF && xSignifier != 0) return NaN;
      else if (xExponent > 16397)
        return xNegative ? POSITIVE_ZERO : POSITIVE_INFINITY;
      else if (xExponent < 16255)
        return 0x3FFF0000000000000000000000000000;
      else {
        if (xExponent == 0) xExponent = 1;
        else xSignifier |= 0x10000000000000000000000000000;

        if (xExponent > 16367)
          xSignifier <<= xExponent - 16367;
        else if (xExponent < 16367)
          xSignifier >>= 16367 - xExponent;

        if (xNegative && xSignifier > 0x406E00000000000000000000000000000000)
          return POSITIVE_ZERO;

        if (!xNegative && xSignifier > 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
          return POSITIVE_INFINITY;

        uint256 resultExponent = xSignifier >> 128;
        xSignifier &= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
        if (xNegative && xSignifier != 0) {
          xSignifier = ~xSignifier;
          resultExponent += 1;
        }

        uint256 resultSignifier = 0x80000000000000000000000000000000;
        if (xSignifier & 0x80000000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x16A09E667F3BCC908B2FB1366EA957D3E >> 128;
        if (xSignifier & 0x40000000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1306FE0A31B7152DE8D5A46305C85EDEC >> 128;
        if (xSignifier & 0x20000000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1172B83C7D517ADCDF7C8C50EB14A791F >> 128;
        if (xSignifier & 0x10000000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10B5586CF9890F6298B92B71842A98363 >> 128;
        if (xSignifier & 0x8000000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1059B0D31585743AE7C548EB68CA417FD >> 128;
        if (xSignifier & 0x4000000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x102C9A3E778060EE6F7CACA4F7A29BDE8 >> 128;
        if (xSignifier & 0x2000000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10163DA9FB33356D84A66AE336DCDFA3F >> 128;
        if (xSignifier & 0x1000000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100B1AFA5ABCBED6129AB13EC11DC9543 >> 128;
        if (xSignifier & 0x800000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10058C86DA1C09EA1FF19D294CF2F679B >> 128;
        if (xSignifier & 0x400000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1002C605E2E8CEC506D21BFC89A23A00F >> 128;
        if (xSignifier & 0x200000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100162F3904051FA128BCA9C55C31E5DF >> 128;
        if (xSignifier & 0x100000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000B175EFFDC76BA38E31671CA939725 >> 128;
        if (xSignifier & 0x80000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100058BA01FB9F96D6CACD4B180917C3D >> 128;
        if (xSignifier & 0x40000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10002C5CC37DA9491D0985C348C68E7B3 >> 128;
        if (xSignifier & 0x20000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000162E525EE054754457D5995292026 >> 128;
        if (xSignifier & 0x10000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000B17255775C040618BF4A4ADE83FC >> 128;
        if (xSignifier & 0x8000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000058B91B5BC9AE2EED81E9B7D4CFAB >> 128;
        if (xSignifier & 0x4000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100002C5C89D5EC6CA4D7C8ACC017B7C9 >> 128;
        if (xSignifier & 0x2000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000162E43F4F831060E02D839A9D16D >> 128;
        if (xSignifier & 0x1000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000B1721BCFC99D9F890EA06911763 >> 128;
        if (xSignifier & 0x800000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000058B90CF1E6D97F9CA14DBCC1628 >> 128;
        if (xSignifier & 0x400000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000002C5C863B73F016468F6BAC5CA2B >> 128;
        if (xSignifier & 0x200000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000162E430E5A18F6119E3C02282A5 >> 128;
        if (xSignifier & 0x100000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000B1721835514B86E6D96EFD1BFE >> 128;
        if (xSignifier & 0x80000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000058B90C0B48C6BE5DF846C5B2EF >> 128;
        if (xSignifier & 0x40000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000002C5C8601CC6B9E94213C72737A >> 128;
        if (xSignifier & 0x20000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000162E42FFF037DF38AA2B219F06 >> 128;
        if (xSignifier & 0x10000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000B17217FBA9C739AA5819F44F9 >> 128;
        if (xSignifier & 0x8000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000058B90BFCDEE5ACD3C1CEDC823 >> 128;
        if (xSignifier & 0x4000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000002C5C85FE31F35A6A30DA1BE50 >> 128;
        if (xSignifier & 0x2000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000162E42FF0999CE3541B9FFFCF >> 128;
        if (xSignifier & 0x1000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000B17217F80F4EF5AADDA45554 >> 128;
        if (xSignifier & 0x800000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000058B90BFBF8479BD5A81B51AD >> 128;
        if (xSignifier & 0x400000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000002C5C85FDF84BD62AE30A74CC >> 128;
        if (xSignifier & 0x200000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000162E42FEFB2FED257559BDAA >> 128;
        if (xSignifier & 0x100000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000B17217F7D5A7716BBA4A9AE >> 128;
        if (xSignifier & 0x80000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000058B90BFBE9DDBAC5E109CCE >> 128;
        if (xSignifier & 0x40000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000002C5C85FDF4B15DE6F17EB0D >> 128;
        if (xSignifier & 0x20000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000162E42FEFA494F1478FDE05 >> 128;
        if (xSignifier & 0x10000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000B17217F7D20CF927C8E94C >> 128;
        if (xSignifier & 0x8000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000058B90BFBE8F71CB4E4B33D >> 128;
        if (xSignifier & 0x4000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000002C5C85FDF477B662B26945 >> 128;
        if (xSignifier & 0x2000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000162E42FEFA3AE53369388C >> 128;
        if (xSignifier & 0x1000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000B17217F7D1D351A389D40 >> 128;
        if (xSignifier & 0x800000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000058B90BFBE8E8B2D3D4EDE >> 128;
        if (xSignifier & 0x400000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000002C5C85FDF4741BEA6E77E >> 128;
        if (xSignifier & 0x200000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000162E42FEFA39FE95583C2 >> 128;
        if (xSignifier & 0x100000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000B17217F7D1CFB72B45E1 >> 128;
        if (xSignifier & 0x80000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000058B90BFBE8E7CC35C3F0 >> 128;
        if (xSignifier & 0x40000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000002C5C85FDF473E242EA38 >> 128;
        if (xSignifier & 0x20000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000162E42FEFA39F02B772C >> 128;
        if (xSignifier & 0x10000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000B17217F7D1CF7D83C1A >> 128;
        if (xSignifier & 0x8000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000058B90BFBE8E7BDCBE2E >> 128;
        if (xSignifier & 0x4000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000002C5C85FDF473DEA871F >> 128;
        if (xSignifier & 0x2000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000162E42FEFA39EF44D91 >> 128;
        if (xSignifier & 0x1000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000B17217F7D1CF79E949 >> 128;
        if (xSignifier & 0x800000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000058B90BFBE8E7BCE544 >> 128;
        if (xSignifier & 0x400000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000002C5C85FDF473DE6ECA >> 128;
        if (xSignifier & 0x200000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000162E42FEFA39EF366F >> 128;
        if (xSignifier & 0x100000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000B17217F7D1CF79AFA >> 128;
        if (xSignifier & 0x80000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000058B90BFBE8E7BCD6D >> 128;
        if (xSignifier & 0x40000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000002C5C85FDF473DE6B2 >> 128;
        if (xSignifier & 0x20000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000162E42FEFA39EF358 >> 128;
        if (xSignifier & 0x10000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000B17217F7D1CF79AB >> 128;
        if (xSignifier & 0x8000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000058B90BFBE8E7BCD5 >> 128;
        if (xSignifier & 0x4000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000002C5C85FDF473DE6A >> 128;
        if (xSignifier & 0x2000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000162E42FEFA39EF34 >> 128;
        if (xSignifier & 0x1000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000B17217F7D1CF799 >> 128;
        if (xSignifier & 0x800000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000058B90BFBE8E7BCC >> 128;
        if (xSignifier & 0x400000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000002C5C85FDF473DE5 >> 128;
        if (xSignifier & 0x200000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000162E42FEFA39EF2 >> 128;
        if (xSignifier & 0x100000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000B17217F7D1CF78 >> 128;
        if (xSignifier & 0x80000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000058B90BFBE8E7BB >> 128;
        if (xSignifier & 0x40000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000002C5C85FDF473DD >> 128;
        if (xSignifier & 0x20000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000162E42FEFA39EE >> 128;
        if (xSignifier & 0x10000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000B17217F7D1CF6 >> 128;
        if (xSignifier & 0x8000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000058B90BFBE8E7A >> 128;
        if (xSignifier & 0x4000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000002C5C85FDF473C >> 128;
        if (xSignifier & 0x2000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000162E42FEFA39D >> 128;
        if (xSignifier & 0x1000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000B17217F7D1CE >> 128;
        if (xSignifier & 0x800000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000058B90BFBE8E6 >> 128;
        if (xSignifier & 0x400000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000002C5C85FDF472 >> 128;
        if (xSignifier & 0x200000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000162E42FEFA38 >> 128;
        if (xSignifier & 0x100000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000B17217F7D1B >> 128;
        if (xSignifier & 0x80000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000058B90BFBE8D >> 128;
        if (xSignifier & 0x40000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000002C5C85FDF46 >> 128;
        if (xSignifier & 0x20000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000162E42FEFA2 >> 128;
        if (xSignifier & 0x10000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000B17217F7D0 >> 128;
        if (xSignifier & 0x8000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000058B90BFBE7 >> 128;
        if (xSignifier & 0x4000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000002C5C85FDF3 >> 128;
        if (xSignifier & 0x2000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000162E42FEF9 >> 128;
        if (xSignifier & 0x1000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000B17217F7C >> 128;
        if (xSignifier & 0x800000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000058B90BFBD >> 128;
        if (xSignifier & 0x400000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000002C5C85FDE >> 128;
        if (xSignifier & 0x200000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000162E42FEE >> 128;
        if (xSignifier & 0x100000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000000B17217F6 >> 128;
        if (xSignifier & 0x80000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000058B90BFA >> 128;
        if (xSignifier & 0x40000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000002C5C85FC >> 128;
        if (xSignifier & 0x20000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000000162E42FD >> 128;
        if (xSignifier & 0x10000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000000B17217E >> 128;
        if (xSignifier & 0x8000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000000058B90BE >> 128;
        if (xSignifier & 0x4000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000002C5C85E >> 128;
        if (xSignifier & 0x2000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000000162E42E >> 128;
        if (xSignifier & 0x1000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000000B17216 >> 128;
        if (xSignifier & 0x800000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000000058B90A >> 128;
        if (xSignifier & 0x400000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000000002C5C84 >> 128;
        if (xSignifier & 0x200000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000000162E41 >> 128;
        if (xSignifier & 0x100000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000000000B1720 >> 128;
        if (xSignifier & 0x80000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000000058B8F >> 128;
        if (xSignifier & 0x40000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000000002C5C7 >> 128;
        if (xSignifier & 0x20000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000000000162E3 >> 128;
        if (xSignifier & 0x10000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000000000B171 >> 128;
        if (xSignifier & 0x8000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000000000058B8 >> 128;
        if (xSignifier & 0x4000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000000002C5B >> 128;
        if (xSignifier & 0x2000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000000000162D >> 128;
        if (xSignifier & 0x1000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000000000B16 >> 128;
        if (xSignifier & 0x800 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000000000058A >> 128;
        if (xSignifier & 0x400 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000000000002C4 >> 128;
        if (xSignifier & 0x200 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000000000161 >> 128;
        if (xSignifier & 0x100 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000000000000B0 >> 128;
        if (xSignifier & 0x80 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000000000057 >> 128;
        if (xSignifier & 0x40 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000000000002B >> 128;
        if (xSignifier & 0x20 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000000000015 >> 128;
        if (xSignifier & 0x10 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000000000000A >> 128;
        if (xSignifier & 0x8 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000000000004 >> 128;
        if (xSignifier & 0x4 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000000000001 >> 128;

        if (!xNegative) {
          resultSignifier = resultSignifier >> 15 & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
          resultExponent += 0x3FFF;
        } else if (resultExponent <= 0x3FFE) {
          resultSignifier = resultSignifier >> 15 & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
          resultExponent = 0x3FFF - resultExponent;
        } else {
          resultSignifier = resultSignifier >> resultExponent - 16367;
          resultExponent = 0;
        }

        return bytes16 (uint128 (resultExponent << 112 | resultSignifier));
      }
    }
  }

  /**
   * Calculate e^x.
   *
   * @param x quadruple precision number
   * @return quadruple precision number
   */
  function exp (bytes16 x) internal pure returns (bytes16) {
    unchecked {
      return pow_2 (mul (x, 0x3FFF71547652B82FE1777D0FFDA0D23A));
    }
  }

  /**
   * Get index of the most significant non-zero bit in binary representation of
   * x.  Reverts if x is zero.
   *
   * @return index of the most significant non-zero bit in binary representation
   *         of x
   */
  function mostSignificantBit (uint256 x) private pure returns (uint256) {
    unchecked {
      require (x > 0);

      uint256 result = 0;

      if (x >= 0x100000000000000000000000000000000) { x >>= 128; result += 128; }
      if (x >= 0x10000000000000000) { x >>= 64; result += 64; }
      if (x >= 0x100000000) { x >>= 32; result += 32; }
      if (x >= 0x10000) { x >>= 16; result += 16; }
      if (x >= 0x100) { x >>= 8; result += 8; }
      if (x >= 0x10) { x >>= 4; result += 4; }
      if (x >= 0x4) { x >>= 2; result += 2; }
      if (x >= 0x2) result += 1; // No need to shift x anymore

      return result;
    }
  }
}

File 20 of 27 : ERC20_Cloneable.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.7;

import "@openzeppelin/contracts/utils/Context.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/proxy/utils/Initializable.sol";

/**
 * @dev Minimal Clones compatible implementation of the {IERC20} interface.
 * @dev Based Openzeppelin 3.4 ERC20 contract
 *
 * 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 guidelines: functions revert instead
 * of 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_Cloneable is Context, ERC20, Initializable {
    uint8 _decimals;
    string private _name;
    string private _symbol;

    address public owner;

    /**
     * @dev Sets the values for {name} and {symbol}, initializes {decimals} with
     * a default value of 18.
     *
     * To select a different value for {decimals}, use {_setupDecimals}.
     *
     * All three of these values are immutable: they can only be set once during
     * construction.
     */
    constructor(
        string memory name_,
        string memory symbol_,
        uint8 decimals_
    ) ERC20(name_, symbol_) {
        _decimals = decimals_;
    }

    function initialize(
        address _pool,
        string memory name_,
        string memory symbol_,
        uint8 decimals_
    ) external initializer {
        owner = _pool;
        _name = name_;
        _symbol = symbol_;
        _decimals = decimals_;
    }

    function decimals() public view virtual override returns (uint8) {
        return _decimals;
    }

    function name() public view virtual override returns (string memory) {
        return _name;
    }

    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @notice Transfer ownership. Implemented to help with initializable
     */
    function transferOwnership(address _owner) external onlyOwner {
        require(_owner != address(0), "Owner: setting to 0 address");
        owner = _owner;
    }

    modifier onlyOwner() {
        require(msg.sender == owner, "msg.sender not owner");
        _;
    }
}

File 21 of 27 : Context.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

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

File 22 of 27 : ERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.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 guidelines: functions revert instead
 * of 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:
     *
     * - `recipient` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
        _transfer(_msgSender(), recipient, 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}.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 amount) public virtual override returns (bool) {
        _approve(_msgSender(), 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}.
     *
     * Requirements:
     *
     * - `sender` and `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     * - the caller must have allowance for ``sender``'s tokens of at least
     * `amount`.
     */
    function transferFrom(
        address sender,
        address recipient,
        uint256 amount
    ) public virtual override returns (bool) {
        _transfer(sender, recipient, amount);

        uint256 currentAllowance = _allowances[sender][_msgSender()];
        require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance");
        unchecked {
            _approve(sender, _msgSender(), currentAllowance - 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) {
        _approve(_msgSender(), spender, _allowances[_msgSender()][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) {
        uint256 currentAllowance = _allowances[_msgSender()][spender];
        require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
        unchecked {
            _approve(_msgSender(), spender, currentAllowance - subtractedValue);
        }

        return true;
    }

    /**
     * @dev Moves `amount` of tokens from `sender` to `recipient`.
     *
     * 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:
     *
     * - `sender` cannot be the zero address.
     * - `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     */
    function _transfer(
        address sender,
        address recipient,
        uint256 amount
    ) internal virtual {
        require(sender != address(0), "ERC20: transfer from the zero address");
        require(recipient != address(0), "ERC20: transfer to the zero address");

        _beforeTokenTransfer(sender, recipient, amount);

        uint256 senderBalance = _balances[sender];
        require(senderBalance >= amount, "ERC20: transfer amount exceeds balance");
        unchecked {
            _balances[sender] = senderBalance - amount;
        }
        _balances[recipient] += amount;

        emit Transfer(sender, recipient, amount);

        _afterTokenTransfer(sender, recipient, 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 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 {}
}

File 23 of 27 : IERC20Metadata.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../IERC20.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);
}

File 24 of 27 : IPoolKeeper.sol
//SPDX-License-Identifier: CC-BY-NC-ND-4.0
pragma solidity 0.8.7;

/// @title The manager contract interface for multiple markets and the pools in them
interface IPoolKeeper {
    // #### Events
    /**
     * @notice Creates a notification when a pool is created
     * @param poolAddress The pool address of the newly created pool
     * @param firstPrice The price of the market oracle when the pool was created
     */
    event PoolAdded(address indexed poolAddress, int256 indexed firstPrice);

    /**
     * @notice Creates a notification when a call to LeveragedPool:poolUpkeep is successful
     * @param pool The pool address being upkept
     * @param data Extra data about the price fetch. This could be roundID in the case of Chainlink Oracles
     * @param startPrice The previous price of the pool
     * @param endPrice The new price of the pool
     */
    event UpkeepSuccessful(address indexed pool, bytes data, int256 indexed startPrice, int256 indexed endPrice);

    /**
     * @notice Creates a notification when a keeper is paid for doing upkeep for a pool
     * @param _pool Address of pool being upkept
     * @param keeper Keeper to be rewarded for upkeeping
     * @param reward Keeper's reward (in settlement tokens)
     */
    event KeeperPaid(address indexed _pool, address indexed keeper, uint256 reward);

    /**
     * @notice Creates a notification when a keeper's payment for upkeeping a pool failed
     * @param _pool Address of pool being upkept
     * @param keeper Keeper to be rewarded for upkeeping
     * @param expectedReward Keeper's expected reward (in settlement tokens); not actually transferred
     */
    event KeeperPaymentError(address indexed _pool, address indexed keeper, uint256 expectedReward);

    /**
     * @notice Creates a notification of a failed pool update
     * @param pool The pool that failed to update
     * @param reason The reason for the error
     */
    event PoolUpkeepError(address indexed pool, string reason);

    // #### Functions
    function newPool(address _poolAddress) external;

    function setFactory(address _factory) external;

    function checkUpkeepSinglePool(address pool) external view returns (bool);

    function checkUpkeepMultiplePools(address[] calldata pools) external view returns (bool);

    function performUpkeepSinglePool(address pool) external;

    function performUpkeepMultiplePools(address[] calldata pools) external;
}

File 25 of 27 : AggregatorV2V3Interface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./AggregatorInterface.sol";
import "./AggregatorV3Interface.sol";

interface AggregatorV2V3Interface is AggregatorInterface, AggregatorV3Interface
{
}

File 26 of 27 : AggregatorInterface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface AggregatorInterface {
  function latestAnswer()
    external
    view
    returns (
      int256
    );
  
  function latestTimestamp()
    external
    view
    returns (
      uint256
    );

  function latestRound()
    external
    view
    returns (
      uint256
    );

  function getAnswer(
    uint256 roundId
  )
    external
    view
    returns (
      int256
    );

  function getTimestamp(
    uint256 roundId
  )
    external
    view
    returns (
      uint256
    );

  event AnswerUpdated(
    int256 indexed current,
    uint256 indexed roundId,
    uint256 updatedAt
  );

  event NewRound(
    uint256 indexed roundId,
    address indexed startedBy,
    uint256 startedAt
  );
}

File 27 of 27 : AggregatorV3Interface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface AggregatorV3Interface {

  function decimals()
    external
    view
    returns (
      uint8
    );

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

  function version()
    external
    view
    returns (
      uint256
    );

  // getRoundData and latestRoundData should both raise "No data present"
  // if they do not have data to report, instead of returning unset values
  // which could be misinterpreted as actual reported values.
  function getRoundData(
    uint80 _roundId
  )
    external
    view
    returns (
      uint80 roundId,
      int256 answer,
      uint256 startedAt,
      uint256 updatedAt,
      uint80 answeredInRound
    );

  function latestRoundData()
    external
    view
    returns (
      uint80 roundId,
      int256 answer,
      uint256 startedAt,
      uint256 updatedAt,
      uint80 answeredInRound
    );

}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  },
  "metadata": {
    "useLiteralContent": true
  },
  "libraries": {
    "contracts/implementation/PoolSwapLibrary.sol": {
      "PoolSwapLibrary": "0x542848e66d8f387a78717be7b39f7259b7782bae"
    }
  }
}

Contract ABI

[{"inputs":[{"internalType":"address","name":"_feeReceiver","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pool","type":"address"},{"indexed":false,"internalType":"string","name":"ticker","type":"string"}],"name":"DeployPool","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"components":[{"internalType":"string","name":"poolName","type":"string"},{"internalType":"uint32","name":"frontRunningInterval","type":"uint32"},{"internalType":"uint32","name":"updateInterval","type":"uint32"},{"internalType":"uint16","name":"leverageAmount","type":"uint16"},{"internalType":"address","name":"quoteToken","type":"address"},{"internalType":"address","name":"oracleWrapper","type":"address"},{"internalType":"address","name":"settlementEthOracle","type":"address"},{"internalType":"uint128","name":"minimumCommitSize","type":"uint128"},{"internalType":"uint128","name":"maximumCommitQueueLength","type":"uint128"}],"internalType":"struct IPoolFactory.PoolDeployment","name":"deploymentParameters","type":"tuple"}],"name":"deployPool","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"fee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeReceiver","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isValidPool","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxLeverage","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"numPools","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pairTokenBase","outputs":[{"internalType":"contract PoolToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pairTokenBaseAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolBase","outputs":[{"internalType":"contract LeveragedPool","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolBaseAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolCommitterDeployer","outputs":[{"internalType":"contract IPoolCommitterDeployer","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolKeeper","outputs":[{"internalType":"contract IPoolKeeper","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"pools","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fee","type":"uint256"}],"name":"setFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_feeReceiver","type":"address"}],"name":"setFeeReceiver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"newMaxLeverage","type":"uint16"}],"name":"setMaxLeverage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_poolCommitterDeployer","type":"address"}],"name":"setPoolCommitterDeployer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_poolKeeper","type":"address"}],"name":"setPoolKeeper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60c06040526004805461ffff60a01b1916600560a11b1790553480156200002557600080fd5b5060405162005a9b38038062005a9b833981016040819052620000489162000332565b6200005333620002c6565b6012604051620000639062000316565b60ff9091168152602001604051809103906000f0801580156200008a573d6000803e3d6000fd5b50600180546001600160a01b0319166001600160a01b03831617905560601b6001600160601b031916608052604051620000c49062000324565b604051809103906000f080158015620000e1573d6000803e3d6000fd5b50600280546001600160a01b0319166001600160a01b038316908117909155606091821b6001600160601b03191660a0908152604080516101c0810182523080825260208083018290528284018290529582018190526080820181905292810183905260c08101839052815180830183526009815268109054d157d413d3d360ba1b9581019590955260e0810194909452600f610100850152601e6101208501526000610140850152600161016085015261018084018290526101a08401919091525163554bb62160e01b815263554bb62190620001c4908490600401620003b4565b600060405180830381600087803b158015620001df57600080fd5b505af1158015620001f4573d6000803e3d6000fd5b5050600154604051637b69774360e11b81523060048083019190915260806024830152600a6084830152692120a9a2afaa27a5a2a760b11b60a483015260c0604483015260c4820152634241534560e01b60e4820152601260648201526001600160a01b03909116925063f6d2ee86915061010401600060405180830381600087803b1580156200028457600080fd5b505af115801562000299573d6000803e3d6000fd5b5050600580546001600160a01b0319166001600160a01b0395909516949094179093555062000507915050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6112108062001c3083390190565b612c5b8062002e4083390190565b6000602082840312156200034557600080fd5b81516001600160a01b03811681146200035d57600080fd5b9392505050565b6000815180845260005b818110156200038c576020818501810151868301820152016200036e565b818111156200039f576000602083870101525b50601f01601f19169290920160200192915050565b60208152620003cf6020820183516001600160a01b03169052565b60006020830151620003ec60408401826001600160a01b03169052565b5060408301516001600160a01b03811660608401525060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c08301516001600160a01b03811660e08401525060e08301516101c06101008181860152620004766101e086018462000364565b90860151909250610120620004928682018363ffffffff169052565b8601519050610140620004ac8682018363ffffffff169052565b860151610160868101919091528601519050610180620004d18187018361ffff169052565b86015190506101a0620004ee868201836001600160a01b03169052565b909501516001600160a01b031693019290925250919050565b60805160601c60a05160601c6116ef620005416000396000818161030d015261072e0152600081816101ce015261102601526116ef6000f3fe608060405234801561001057600080fd5b50600436106101425760003560e01c8063715018a6116100b8578063b3f006741161007c578063b3f00674146102d9578063d723c68b146102ec578063ddca3f43146102ff578063ed3f7e2614610308578063efdcd9741461032f578063f2fde38b1461034257600080fd5b8063715018a61461026f578063893d20e8146102775780638da5cb5b14610277578063ac4afa3814610288578063ae3302c2146102b157600080fd5b80634690092c1161010a5780634690092c146101c9578063568212f6146101f05780635ab78ee1146102035780635bae377a1461023657806367e047561461024957806369fe0e2d1461025c57600080fd5b80630679d36214610147578063178f9e351461015c57806335c62bc21461018c57806340339cbf146101a3578063430ed6eb146101b6575b600080fd5b61015a6101553660046111b1565b610355565b005b60035461016f906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b61019560085481565b604051908152602001610183565b61016f6101b136600461114c565b610408565b61015a6101c436600461110b565b610c07565b61016f7f000000000000000000000000000000000000000000000000000000000000000081565b61015a6101fe36600461110b565b610c79565b61022661021136600461110b565b60096020526000908152604090205460ff1681565b6040519015158152602001610183565b60025461016f906001600160a01b031681565b60045461016f906001600160a01b031681565b61015a61026a3660046111d5565b610ceb565b61015a610d1a565b6000546001600160a01b031661016f565b61016f6102963660046111d5565b6007602052600090815260409020546001600160a01b031681565b6004546102c690600160a01b900461ffff1681565b60405161ffff9091168152602001610183565b60055461016f906001600160a01b031681565b60015461016f906001600160a01b031681565b61019560065481565b61016f7f000000000000000000000000000000000000000000000000000000000000000081565b61015a61033d36600461110b565b610d50565b61015a61035036600461110b565b610dc2565b6000546001600160a01b031633146103885760405162461bcd60e51b815260040161037f90611384565b60405180910390fd5b60008161ffff16116103e65760405162461bcd60e51b815260206004820152602160248201527f4d6178696d756d206c65766572616765206d757374206265206e6f6e2d7a65726044820152606f60f81b606482015260840161037f565b6004805461ffff909216600160a01b0261ffff60a01b19909216919091179055565b600080546001600160a01b031633146104635760405162461bcd60e51b815260206004820152601960248201527f6d73672e73656e646572206e6f7420676f7665726e616e636500000000000000604482015260640161037f565b6003546001600160a01b0316806104b15760405162461bcd60e51b8152602060048201526012602482015271141bdbdb12d9595c195c881b9bdd081cd95d60721b604482015260640161037f565b6004546001600160a01b03166105095760405162461bcd60e51b815260206004820152601d60248201527f506f6f6c436f6d6d69747465724465706c6f796572206e6f7420736574000000604482015260640161037f565b6004546000906001600160a01b0316639604198361052e610100870160e08801611188565b61054061012088016101008901611188565b6040516001600160e01b031960e085901b1681526001600160801b03928316600482015291166024820152604401602060405180830381600087803b15801561058857600080fd5b505af115801561059c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105c0919061112f565b905060016105d460808601606087016111b1565b61ffff16101580156106065750600454600160a01b900461ffff166105ff60808601606087016111b1565b61ffff1611155b61065e5760405162461bcd60e51b8152602060048201526024808201527f506f6f6c4b65657065723a206c657665726167656420616d6f756e7420696e76604482015263185b1a5960e21b606482015260840161037f565b601261067060a086016080870161110b565b6001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b1580156106a857600080fd5b505afa1580156106bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106e09190611214565b60ff1611156107275760405162461bcd60e51b81526020600482015260136024820152720a8ded6cadc40c8cac6d2dac2d8e6407c40627606b1b604482015260640161037f565b60006107527f0000000000000000000000000000000000000000000000000000000000000000610e5d565b9050806001600160a01b0381167fd76cdb035f3aba359cb02087e4c5bd75f911562b407fc3a52ed2bedfb46585b661078a8880611534565b604051610798929190611355565b60405180910390a260006107be6107b56080890160608a016111b1565b61ffff16610ef5565b90506000816107cd8980611534565b6040516020016107df93929190611263565b60408051601f1981840301815291905290506000826107fe8a80611534565b6040516020016108109392919061129b565b60408051601f198184030181529190529050600061083460a08b0160808c0161110b565b6001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561086c57600080fd5b505afa158015610880573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108a49190611214565b905060006108b48684858561101e565b905060006108c48786878661101e565b90506000604051806101c001604052806108e66000546001600160a01b031690565b6001600160a01b031681526020018c6001600160a01b031681526020018e60a0016020810190610916919061110b565b6001600160a01b031681526020018e60c0016020810190610937919061110b565b6001600160a01b03168152602001836001600160a01b03168152602001846001600160a01b031681526020018b6001600160a01b03168152602001888f80600001906109839190611534565b604051602001610995939291906112d3565b60405160208183030381529060405281526020018e60200160208101906109bc91906111ee565b63ffffffff1681526020018e60400160208101906109da91906111ee565b63ffffffff16815260200160065481526020018e6060016020810190610a0091906111b1565b61ffff168152602001600560009054906101000a90046001600160a01b03166001600160a01b031681526020018e6080016020810190610a40919061110b565b6001600160a01b03168152509050886001600160a01b031663554bb621826040518263ffffffff1660e01b8152600401610a7a91906113e9565b600060405180830381600087803b158015610a9457600080fd5b505af1158015610aa8573d6000803e3d6000fd5b50505050896001600160a01b031663fd555fb98e6080016020810190610ace919061110b565b6040516001600160e01b031960e084901b1681526001600160a01b039182166004820152908b166024820152604401600060405180830381600087803b158015610b1757600080fd5b505af1158015610b2b573d6000803e3d6000fd5b5050600354604051633c5c7fb360e01b81526001600160a01b038c811660048301529091169250633c5c7fb39150602401600060405180830381600087803b158015610b7657600080fd5b505af1158015610b8a573d6000803e3d6000fd5b505060088054600090815260076020526040812080546001600160a01b0319166001600160a01b038e1617905581546001945091925090610bcc908490611582565b9091555050506001600160a01b0387166000908152600960205260409020805460ff191660011790555094985050505050505050505b919050565b6000546001600160a01b03163314610c315760405162461bcd60e51b815260040161037f90611384565b6001600160a01b038116610c575760405162461bcd60e51b815260040161037f906113b9565b600380546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b03163314610ca35760405162461bcd60e51b815260040161037f90611384565b6001600160a01b038116610cc95760405162461bcd60e51b815260040161037f906113b9565b600480546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b03163314610d155760405162461bcd60e51b815260040161037f90611384565b600655565b6000546001600160a01b03163314610d445760405162461bcd60e51b815260040161037f90611384565b610d4e60006110bb565b565b6000546001600160a01b03163314610d7a5760405162461bcd60e51b815260040161037f90611384565b6001600160a01b038116610da05760405162461bcd60e51b815260040161037f906113b9565b600580546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b03163314610dec5760405162461bcd60e51b815260040161037f90611384565b6001600160a01b038116610e515760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161037f565b610e5a816110bb565b50565b6000604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b81528260601b60148201526e5af43d82803e903d91602b57fd5bf360881b60288201526037816000f09150506001600160a01b038116610c025760405162461bcd60e51b8152602060048201526016602482015275115490cc4c4d8dce8818dc99585d194819985a5b195960521b604482015260640161037f565b606081610f195750506040805180820190915260018152600360fc1b602082015290565b8160005b8115610f435780610f2d81611647565b9150610f3c9050600a836115bf565b9150610f1d565b60008167ffffffffffffffff811115610f5e57610f5e61168e565b6040519080825280601f01601f191660200182016040528015610f88576020820181803683370190505b509050815b851561101557610f9e600182611600565b90506000610fad600a886115bf565b610fb890600a6115e1565b610fc29088611600565b610fcd90603061159a565b905060008160f81b905080848481518110610fea57610fea611678565b60200101906001600160f81b031916908160001a90535061100c600a896115bf565b97505050610f8d565b50949350505050565b60008061104a7f0000000000000000000000000000000000000000000000000000000000000000610e5d565b604051637b69774360e11b81529091506001600160a01b0382169063f6d2ee869061107f90899089908990899060040161130a565b600060405180830381600087803b15801561109957600080fd5b505af11580156110ad573d6000803e3d6000fd5b509298975050505050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60006020828403121561111d57600080fd5b8135611128816116a4565b9392505050565b60006020828403121561114157600080fd5b8151611128816116a4565b60006020828403121561115e57600080fd5b813567ffffffffffffffff81111561117557600080fd5b8201610120818503121561112857600080fd5b60006020828403121561119a57600080fd5b81356001600160801b038116811461112857600080fd5b6000602082840312156111c357600080fd5b813561ffff8116811461112857600080fd5b6000602082840312156111e757600080fd5b5035919050565b60006020828403121561120057600080fd5b813563ffffffff8116811461112857600080fd5b60006020828403121561122657600080fd5b815160ff8116811461112857600080fd5b6000815180845261124f816020860160208601611617565b601f01601f19169290920160200192915050565b60008451611275818460208901611617565b614c2d60f01b908301908152838560028301376000930160020192835250909392505050565b600084516112ad818460208901611617565b61532d60f01b908301908152838560028301376000930160020192835250909392505050565b600084516112e5818460208901611617565b602d60f81b908301908152838560018301376000930160010192835250909392505050565b6001600160a01b038516815260806020820181905260009061132e90830186611237565b82810360408401526113408186611237565b91505060ff8316606083015295945050505050565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252601690820152751859191c995cdcc818d85b9b9bdd081899481b9d5b1b60521b604082015260600190565b602081526114036020820183516001600160a01b03169052565b6000602083015161141f60408401826001600160a01b03169052565b5060408301516001600160a01b03811660608401525060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c08301516001600160a01b03811660e08401525060e08301516101c061010081818601526114a76101e0860184611237565b908601519092506101206114c28682018363ffffffff169052565b86015190506101406114db8682018363ffffffff169052565b8601516101608681019190915286015190506101806114ff8187018361ffff169052565b86015190506101a061151b868201836001600160a01b03169052565b909501516001600160a01b031693019290925250919050565b6000808335601e1984360301811261154b57600080fd5b83018035915067ffffffffffffffff82111561156657600080fd5b60200191503681900382131561157b57600080fd5b9250929050565b6000821982111561159557611595611662565b500190565b600060ff821660ff84168060ff038211156115b7576115b7611662565b019392505050565b6000826115dc57634e487b7160e01b600052601260045260246000fd5b500490565b60008160001904831182151516156115fb576115fb611662565b500290565b60008282101561161257611612611662565b500390565b60005b8381101561163257818101518382015260200161161a565b83811115611641576000848401525b50505050565b600060001982141561165b5761165b611662565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114610e5a57600080fdfea26469706673582212201fae6fbed720990652cf3a5ffc0343c1ecd694a5037b6c5be000ef40f617c45964736f6c6343000807003360806040523480156200001157600080fd5b506040516200121038038062001210833981016040819052620000349162000175565b6040518060400160405280600a8152602001692120a9a2afaa27a5a2a760b11b815250604051806040016040528060048152602001634241534560e01b81525082828281600390805190602001906200008f929190620000cf565b508051620000a5906004906020840190620000cf565b50506005805460ff909316620100000262ff0000199093169290921790915550620001de92505050565b828054620000dd90620001a1565b90600052602060002090601f0160209004810192826200010157600085556200014c565b82601f106200011c57805160ff19168380011785556200014c565b828001600101855582156200014c579182015b828111156200014c5782518255916020019190600101906200012f565b506200015a9291506200015e565b5090565b5b808211156200015a57600081556001016200015f565b6000602082840312156200018857600080fd5b815160ff811681146200019a57600080fd5b9392505050565b600181811c90821680620001b657607f821691505b60208210811415620001d857634e487b7160e01b600052602260045260246000fd5b50919050565b61102280620001ee6000396000f3fe608060405234801561001057600080fd5b50600436106101005760003560e01c806394bf804d11610097578063dd62ed3e11610066578063dd62ed3e14610231578063f2fde38b1461026a578063f6d2ee861461027f578063fcd3533c1461029257600080fd5b806394bf804d146101f057806395d89b4114610203578063a457c2d71461020b578063a9059cbb1461021e57600080fd5b8063313ce567116100d3578063313ce5671461016b578063395093511461018957806370a082311461019c5780638da5cb5b146101c557600080fd5b806306fdde0314610105578063095ea7b31461012357806318160ddd1461014657806323b872dd14610158575b600080fd5b61010d6102a5565b60405161011a9190610ed3565b60405180910390f35b610136610131366004610e86565b610337565b604051901515815260200161011a565b6002545b60405190815260200161011a565b610136610166366004610dbd565b61034d565b60055462010000900460ff1660405160ff909116815260200161011a565b610136610197366004610e86565b6103fc565b61014a6101aa366004610d68565b6001600160a01b031660009081526020819052604090205490565b6008546101d8906001600160a01b031681565b6040516001600160a01b03909116815260200161011a565b6101366101fe366004610eb0565b610438565b61010d61046f565b610136610219366004610e86565b61047e565b61013661022c366004610e86565b610517565b61014a61023f366004610d8a565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b61027d610278366004610d68565b610524565b005b61027d61028d366004610df9565b6105c6565b6101366102a0366004610eb0565b6106d6565b6060600680546102b490610f85565b80601f01602080910402602001604051908101604052809291908181526020018280546102e090610f85565b801561032d5780601f106103025761010080835404028352916020019161032d565b820191906000526020600020905b81548152906001019060200180831161031057829003601f168201915b5050505050905090565b600061034433848461070d565b50600192915050565b600061035a848484610832565b6001600160a01b0384166000908152600160209081526040808320338452909152902054828110156103e45760405162461bcd60e51b815260206004820152602860248201527f45524332303a207472616e7366657220616d6f756e74206578636565647320616044820152676c6c6f77616e636560c01b60648201526084015b60405180910390fd5b6103f1853385840361070d565b506001949350505050565b3360008181526001602090815260408083206001600160a01b03871684529091528120549091610344918590610433908690610f56565b61070d565b6008546000906001600160a01b031633146104655760405162461bcd60e51b81526004016103db90610f28565b6103448284610a01565b6060600780546102b490610f85565b3360009081526001602090815260408083206001600160a01b0386168452909152812054828110156105005760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016103db565b61050d338585840361070d565b5060019392505050565b6000610344338484610832565b6008546001600160a01b0316331461054e5760405162461bcd60e51b81526004016103db90610f28565b6001600160a01b0381166105a45760405162461bcd60e51b815260206004820152601b60248201527f4f776e65723a2073657474696e6720746f20302061646472657373000000000060448201526064016103db565b600880546001600160a01b0319166001600160a01b0392909216919091179055565b600554610100900460ff16806105df575060055460ff16155b6106425760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016103db565b600554610100900460ff16158015610664576005805461ffff19166101011790555b600880546001600160a01b0319166001600160a01b0387161790558351610692906006906020870190610c26565b5082516106a6906007906020860190610c26565b506005805462ff000019166201000060ff85160217905580156106cf576005805461ff00191690555b5050505050565b6008546000906001600160a01b031633146107035760405162461bcd60e51b81526004016103db90610f28565b6103448284610ae0565b6001600160a01b03831661076f5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016103db565b6001600160a01b0382166107d05760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016103db565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b6001600160a01b0383166108965760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016103db565b6001600160a01b0382166108f85760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016103db565b6001600160a01b038316600090815260208190526040902054818110156109705760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016103db565b6001600160a01b038085166000908152602081905260408082208585039055918516815290812080548492906109a7908490610f56565b92505081905550826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516109f391815260200190565b60405180910390a350505050565b6001600160a01b038216610a575760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016103db565b8060026000828254610a699190610f56565b90915550506001600160a01b03821660009081526020819052604081208054839290610a96908490610f56565b90915550506040518181526001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b6001600160a01b038216610b405760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016103db565b6001600160a01b03821660009081526020819052604090205481811015610bb45760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016103db565b6001600160a01b0383166000908152602081905260408120838303905560028054849290610be3908490610f6e565b90915550506040518281526000906001600160a01b038516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90602001610825565b828054610c3290610f85565b90600052602060002090601f016020900481019282610c545760008555610c9a565b82601f10610c6d57805160ff1916838001178555610c9a565b82800160010185558215610c9a579182015b82811115610c9a578251825591602001919060010190610c7f565b50610ca6929150610caa565b5090565b5b80821115610ca65760008155600101610cab565b80356001600160a01b0381168114610cd657600080fd5b919050565b600082601f830112610cec57600080fd5b813567ffffffffffffffff80821115610d0757610d07610fd6565b604051601f8301601f19908116603f01168101908282118183101715610d2f57610d2f610fd6565b81604052838152866020858801011115610d4857600080fd5b836020870160208301376000602085830101528094505050505092915050565b600060208284031215610d7a57600080fd5b610d8382610cbf565b9392505050565b60008060408385031215610d9d57600080fd5b610da683610cbf565b9150610db460208401610cbf565b90509250929050565b600080600060608486031215610dd257600080fd5b610ddb84610cbf565b9250610de960208501610cbf565b9150604084013590509250925092565b60008060008060808587031215610e0f57600080fd5b610e1885610cbf565b9350602085013567ffffffffffffffff80821115610e3557600080fd5b610e4188838901610cdb565b94506040870135915080821115610e5757600080fd5b50610e6487828801610cdb565b925050606085013560ff81168114610e7b57600080fd5b939692955090935050565b60008060408385031215610e9957600080fd5b610ea283610cbf565b946020939093013593505050565b60008060408385031215610ec357600080fd5b82359150610db460208401610cbf565b600060208083528351808285015260005b81811015610f0057858101830151858201604001528201610ee4565b81811115610f12576000604083870101525b50601f01601f1916929092016040019392505050565b60208082526014908201527336b9b39739b2b73232b9103737ba1037bbb732b960611b604082015260600190565b60008219821115610f6957610f69610fc0565b500190565b600082821015610f8057610f80610fc0565b500390565b600181811c90821680610f9957607f821691505b60208210811415610fba57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fdfea26469706673582212207c87cda234a81f67da55383e6777723cd02e3646c72a9ac54ed0abd1942c4c2864736f6c63430008070033608060405234801561001057600080fd5b50612c3b806100206000396000f3fe608060405234801561001057600080fd5b506004361061023d5760003560e01c80637bbf10331161013b578063b9ed8abf116100b8578063ddca3f431161007c578063ddca3f43146104de578063f164e2a7146104f2578063f3466dfa14610506578063f633a7401461051b578063fd2c80ae1461052e57600080fd5b8063b9ed8abf14610489578063ba8d54681461049c578063bbcaac38146104a5578063cd39f30f146104b8578063d38bfff4146104cb57600080fd5b80638456cb59116100ff5780638456cb591461042257806387f9ca5d1461042a5780639fd552451461043d578063ab47c2b314610450578063aced16611461047657600080fd5b80637bbf1033146103d05780637bfe789a146103d85780637de93f93146103fd5780637e71fc7d146104065780638226f3961461040f57600080fd5b80635aa6e675116101c9578063748747e61161018d578063748747e61461036657806375c66e2f14610379578063796da7af1461038c5780637b0a0c90146103a25780637bb98a68146103b557600080fd5b80635aa6e675146102ff5780635c975abb146103125780635d36b190146103365780636d3e313e1461033e5780636dc2b2711461035357600080fd5b80633f4ba83a116102105780633f4ba83a146102ab57806341275358146102b35780634f64b2be146102c6578063554bb621146102d95780635817f0c6146102ec57600080fd5b806304883c2714610242578063217a4b70146102635780633c3f82521461028e5780633d4c485d146102a3575b600080fd5b61024a610546565b60405161025a94939291906129c3565b60405180910390f35b600a54610276906001600160a01b031681565b6040516001600160a01b03909116815260200161025a565b6102a161029c3660046127b9565b6105f9565b005b6102a1610661565b6102a1610771565b600954610276906001600160a01b031681565b6102766102d436600461283b565b6107d3565b6102a16102e73660046127db565b6107f3565b6102a16102fa366004612671565b61117d565b600754610276906001600160a01b031681565b60105461032690600160a81b900460ff1681565b604051901515815260200161025a565b6102a161123e565b61034661137c565b60405161025a9190612989565b610326610361366004612671565b6113c0565b6102a161037436600461261a565b61158a565b6102a1610387366004612878565b611691565b610394611871565b60405190815260200161025a565b6102a16103b0366004612635565b6118f3565b6001546002546040805192835260208301919091520161025a565b610326611a0b565b6003546103e89063ffffffff1681565b60405163ffffffff909116815260200161025a565b610394600c5481565b61039460025481565b600f54610276906001600160a01b031681565b6102a1611a35565b6102a1610438366004612878565b611a9d565b601054610276906001600160a01b031681565b60045461045d9060801b81565b6040516001600160801b0319909116815260200161025a565b600854610276906001600160a01b031681565b600e54610276906001600160a01b031681565b61039460015481565b6102a16104b336600461261a565b611c78565b600b54610276906001600160a01b031681565b6102a16104d936600461261a565b611d74565b60035461045d90600160401b900460801b81565b60105461032690600160a01b900460ff1681565b61050e611e83565b60405161025a91906129ef565b6102a16105293660046127b9565b611f11565b6003546103e890640100000000900463ffffffff1681565b60006060600080600e60009054906101000a90046001600160a01b03166001600160a01b031663db6d8fcf6040518163ffffffff1660e01b815260040160006040518083038186803b15801561059b57600080fd5b505afa1580156105af573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526105d79190810190612700565b600c546003549297919650945064010000000090910463ffffffff1692509050565b600b546001600160a01b0316331461062c5760405162461bcd60e51b815260040161062390612a2a565b60405180910390fd5b601054600160a81b900460ff16156106565760405162461bcd60e51b815260040161062390612a02565b600291909155600155565b6007546001600160a01b0316331461068b5760405162461bcd60e51b815260040161062390612a61565b601054600160a81b900460ff166106d35760405162461bcd60e51b815260206004820152600c60248201526b506f6f6c206973206c69766560a01b6044820152606401610623565b600a546040516370a0823160e01b81523060048201526001600160a01b039091169060009082906370a082319060240160206040518083038186803b15801561071b57600080fd5b505afa15801561072f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061075391906126e7565b600a5490915061076d906001600160a01b0316338361205b565b5050565b6007546001600160a01b0316331461079b5760405162461bcd60e51b815260040161062390612a61565b6010805460ff60a81b191690556040517fa45f47fdea8a1efdd9029a5691c7f759c32b7c698632b563573e155625d1693390600090a1565b600581600281106107e357600080fd5b01546001600160a01b0316905081565b600054610100900460ff168061080c575060005460ff16155b61086f5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610623565b600054610100900460ff16158015610891576000805461ffff19166101011790555b60006108a56101a08401610180850161261a565b6001600160a01b031614156108fc5760405162461bcd60e51b815260206004820152601f60248201527f46656520616464726573732063616e6e6f7420626520302061646472657373006044820152606401610623565b60006109106101c084016101a0850161261a565b6001600160a01b031614156109675760405162461bcd60e51b815260206004820152601f60248201527f51756f746520746f6b656e2063616e6e6f7420626520302061646472657373006044820152606401610623565b6000610979606084016040850161261a565b6001600160a01b031614156109db5760405162461bcd60e51b815260206004820152602260248201527f4f7261636c6520777261707065722063616e6e6f742062652030206164647265604482015261737360f01b6064820152608401610623565b60006109ed608084016060850161261a565b6001600160a01b03161415610a4e5760405162461bcd60e51b815260206004820152602160248201527f4b6565706572206f7261636c652063616e6e6f742062652030206164647265736044820152607360f81b6064820152608401610623565b6000610a5d602084018461261a565b6001600160a01b03161415610ab45760405162461bcd60e51b815260206004820152601960248201527f4f776e65722063616e6e6f7420626520302061646472657373000000000000006044820152606401610623565b6000610ac6604084016020850161261a565b6001600160a01b03161415610b1d5760405162461bcd60e51b815260206004820152601a60248201527f4b65657065722063616e6e6f74206265203020616464726573730000000000006044820152606401610623565b6000610b2f60a084016080850161261a565b6001600160a01b03161415610b865760405162461bcd60e51b815260206004820152601e60248201527f4c6f6e6720746f6b656e2063616e6e6f742062652030206164647265737300006044820152606401610623565b6000610b9860c0840160a0850161261a565b6001600160a01b03161415610bef5760405162461bcd60e51b815260206004820152601f60248201527f53686f727420746f6b656e2063616e6e6f7420626520302061646472657373006044820152606401610623565b6000610c0160e0840160c0850161261a565b6001600160a01b03161415610c625760405162461bcd60e51b815260206004820152602160248201527f506f6f6c436f6d6d69747465722063616e6e6f742062652030206164647265736044820152607360f81b6064820152608401610623565b610c74610140830161012084016128db565b63ffffffff16610c8c610120840161010085016128db565b63ffffffff1610610cdf5760405162461bcd60e51b815260206004820152601d60248201527f66726f6e7452756e6e696e67203e20757064617465496e74657276616c0000006044820152606401610623565b610cf2670de0b6b3a76400006001612afe565b82610140013510610d335760405162461bcd60e51b815260206004820152600b60248201526a466565203e3d203130302560a81b6044820152606401610623565b610d40602083018361261a565b600780546001600160a01b0319166001600160a01b0392909216919091179055610d70604083016020840161261a565b600880546001600160a01b0319166001600160a01b0392909216919091179055610da0606083016040840161261a565b600e80546001600160a01b0319166001600160a01b0392909216919091179055610dd0608083016060840161261a565b600f80546001600160a01b0319166001600160a01b0392909216919091179055610e026101c083016101a0840161261a565b600a80546001600160a01b0319166001600160a01b0392909216919091179055610e34610120830161010084016128db565b6003805463ffffffff191663ffffffff92909216919091179055610e60610140830161012084016128db565b6003805463ffffffff929092166401000000000267ffffffff0000000019909216919091179055604051636fedf26d60e11b8152610140830135600482015273542848e66d8f387a78717be7b39f7259b7782bae9063dfdbe4da9060240160206040518083038186803b158015610ed657600080fd5b505af4158015610eea573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f0e91906126bd565b6003805460809290921c600160401b0277ffffffffffffffffffffffffffffffff00000000000000001990921691909117905573542848e66d8f387a78717be7b39f7259b7782bae63dfdbe4da610f6d61018085016101608601612817565b6040516001600160e01b031960e084901b16815261ffff909116600482015260240160206040518083038186803b158015610fa757600080fd5b505af4158015610fbb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fdf91906126bd565b600480546001600160801b03191660809290921c91909117905561100b6101a08301610180840161261a565b600980546001600160a01b0319166001600160a01b039290921691909117905542600c5561103c60e0830183612a98565b61104891600d91612547565b5061105960a083016080840161261a565b600560000180546001600160a01b0319166001600160a01b039290921691909117905561108c60c0830160a0840161261a565b600560010180546001600160a01b0319166001600160a01b03929092169190911790556110bf60e0830160c0840161261a565b600b80546001600160a01b0319166001600160a01b03929092169190911790556110ef60c0830160a0840161261a565b6001600160a01b031661110860a084016080850161261a565b6001600160a01b03167fbc8bd61e5dd69ff5cb8c389529c029503515ba368eaafbdaa406e072fdd360726111446101c086016101a0870161261a565b61115160e0870187612a98565b60405161116093929190612949565b60405180910390a3801561076d576000805461ff00191690555050565b600b546001600160a01b031633146111a75760405162461bcd60e51b815260040161062390612a2a565b601054600160a81b900460ff16156111d15760405162461bcd60e51b815260040161062390612a02565b6001600160a01b0382166112275760405162461bcd60e51b815260206004820152601e60248201527f546f20616464726573732063616e6e6f742062652030206164647265737300006044820152606401610623565b600a5461076d906001600160a01b0316838361205b565b601054600160a81b900460ff16156112685760405162461bcd60e51b815260040161062390612a02565b601054600160a01b900460ff166112c15760405162461bcd60e51b815260206004820152601b60248201527f4e6f20676f7665726e616e6365206368616e67652061637469766500000000006044820152606401610623565b6010546001600160a01b0316331461131b5760405162461bcd60e51b815260206004820152601860248201527f4e6f742070726f766973696f6e616c20676f7665726e6f7200000000000000006044820152606401610623565b60078054601080546001600160a01b038082166001600160a01b03198516811790955560ff60a01b199091169091556040519116919082907f023588d3d1dcaad34e471c9e01b616b794156174bc693539c8fe15c0bfd5d82690600090a350565b6113846125cb565b60408051808201918290529060059060029082845b81546001600160a01b03168152600190910190602001808311611399575050505050905090565b6008546000906001600160a01b031633146114155760405162461bcd60e51b815260206004820152601560248201527436b9b39739b2b73232b9103737ba1035b2b2b832b960591b6044820152606401610623565b601054600160a81b900460ff161561143f5760405162461bcd60e51b815260040161062390612a02565b6001600160a01b03831661149f5760405162461bcd60e51b815260206004820152602160248201527f52656365697069656e7420616464726573732063616e6e6f74206265206e756c6044820152601b60fa1b6064820152608401610623565b6001546002546114af8183612ae6565b84106114c057600092505050611584565b60405163dc35bc1360e01b8152600481018590526024810183905260448101829052600090819073542848e66d8f387a78717be7b39f7259b7782bae9063dc35bc1390606401604080518083038186803b15801561151d57600080fd5b505af4158015611531573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115559190612854565b60018290556002819055600a54919350915061157b906001600160a01b0316888861205b565b60019450505050505b92915050565b6007546001600160a01b031633146115b45760405162461bcd60e51b815260040161062390612a61565b601054600160a81b900460ff16156115de5760405162461bcd60e51b815260040161062390612a02565b6001600160a01b03811661163f5760405162461bcd60e51b815260206004820152602260248201527f4b656570657220616464726573732063616e6e6f742062652030206164647265604482015261737360f01b6064820152608401610623565b600880546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f402b3f9a8de3e388e7653c7a5892204fe18b579c8c23db19d6e00f1043ceb92190600090a35050565b600b546001600160a01b031633146116bb5760405162461bcd60e51b815260040161062390612a2a565b601054600160a81b900460ff16156116e55760405162461bcd60e51b815260040161062390612a02565b6001600160a01b0381166117465760405162461bcd60e51b815260206004820152602260248201527f4d696e74657220616464726573732063616e6e6f742062652030206164647265604482015261737360f01b6064820152608401610623565b8215806117535750826001145b61179a5760405162461bcd60e51b8152602060048201526018602482015277506f6f6c3a20746f6b656e206f7574206f662072616e676560401b6044820152606401610623565b600583600281106117ad576117ad612bd9565b01546040516394bf804d60e01b8152600481018490526001600160a01b038381166024830152909116906394bf804d90604401602060405180830381600087803b1580156117fa57600080fd5b505af115801561180e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611832919061269b565b61186c5760405162461bcd60e51b815260206004820152600b60248201526a135a5b9d0819985a5b195960aa1b6044820152606401610623565b505050565b600e5460408051634c6afee560e11b815290516000926001600160a01b0316916398d5fdca916004808301926020929190829003018186803b1580156118b657600080fd5b505afa1580156118ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118ee91906126e7565b905090565b600b546001600160a01b0316331461191d5760405162461bcd60e51b815260040161062390612a2a565b601054600160a81b900460ff16156119475760405162461bcd60e51b815260040161062390612a02565b6001600160a01b03831661199d5760405162461bcd60e51b815260206004820181905260248201527f46726f6d20616464726573732063616e6e6f74206265203020616464726573736044820152606401610623565b6001600160a01b0382166119f35760405162461bcd60e51b815260206004820152601e60248201527f546f20616464726573732063616e6e6f742062652030206164647265737300006044820152606401610623565b600a5461186c906001600160a01b03168484846120be565b600354600c54600091611a2d9164010000000090910463ffffffff1690612ae6565b421015905090565b6007546001600160a01b03163314611a5f5760405162461bcd60e51b815260040161062390612a61565b6010805460ff60a81b1916600160a81b1790556040517f9e87fac88ff661f02d44f95383c817fece4bce600a3dab7a54406878b965e75290600090a1565b600b546001600160a01b03163314611ac75760405162461bcd60e51b815260040161062390612a2a565b601054600160a81b900460ff1615611af15760405162461bcd60e51b815260040161062390612a02565b6001600160a01b038116611b525760405162461bcd60e51b815260206004820152602260248201527f4275726e657220616464726573732063616e6e6f742062652030206164647265604482015261737360f01b6064820152608401610623565b821580611b5f5750826001145b611ba65760405162461bcd60e51b8152602060048201526018602482015277506f6f6c3a20746f6b656e206f7574206f662072616e676560401b6044820152606401610623565b60058360028110611bb957611bb9612bd9565b0154604051633f34d4cf60e21b8152600481018490526001600160a01b0383811660248301529091169063fcd3533c90604401602060405180830381600087803b158015611c0657600080fd5b505af1158015611c1a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c3e919061269b565b61186c5760405162461bcd60e51b815260206004820152600b60248201526a109d5c9b8819985a5b195960aa1b6044820152606401610623565b6007546001600160a01b03163314611ca25760405162461bcd60e51b815260040161062390612a61565b601054600160a81b900460ff1615611ccc5760405162461bcd60e51b815260040161062390612a02565b6001600160a01b038116611d225760405162461bcd60e51b815260206004820152601b60248201527f4163636f756e742063616e6e6f742062652030206164647265737300000000006044820152606401610623565b600980546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f11f35a22548bcd4c3788ab4a7e4fba427a2014f02e5d5e2da9af62212c03183f90600090a35050565b6007546001600160a01b03163314611d9e5760405162461bcd60e51b815260040161062390612a61565b601054600160a81b900460ff1615611dc85760405162461bcd60e51b815260040161062390612a02565b6001600160a01b038116611e2d5760405162461bcd60e51b815260206004820152602660248201527f476f7665726e616e636520616464726573732063616e6e6f742062652030206160448201526564647265737360d01b6064820152608401610623565b601080546001600160a81b0319166001600160a01b0380841691909117600160a01b17918290556040519116907f35681f4f23137fb58510a9854f1b6e95f90a2cf0b66d2fce4df74cc0becc82d590600090a250565b600d8054611e9090612b88565b80601f0160208091040260200160405190810160405280929190818152602001828054611ebc90612b88565b8015611f095780601f10611ede57610100808354040283529160200191611f09565b820191906000526020600020905b815481529060010190602001808311611eec57829003601f168201915b505050505081565b6008546001600160a01b03163314611f635760405162461bcd60e51b815260206004820152601560248201527436b9b39739b2b73232b9103737ba1035b2b2b832b960591b6044820152606401610623565b601054600160a81b900460ff1615611f8d5760405162461bcd60e51b815260040161062390612a02565b611f95611a0b565b611fe15760405162461bcd60e51b815260206004820152601d60248201527f55706461746520696e74657276616c206861736e2774207061737365640000006044820152606401610623565b611feb82826120fc565b600b60009054906101000a90046001600160a01b03166001600160a01b0316631c536da46040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561203b57600080fd5b505af115801561204f573d6000803e3d6000fd5b505042600c5550505050565b6040516001600160a01b03831660248201526044810182905261186c90849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526122fb565b6040516001600160a01b03808516602483015283166044820152606481018290526120f69085906323b872dd60e01b90608401612087565b50505050565b601054600160a81b900460ff16156121265760405162461bcd60e51b815260040161062390612a02565b600082131580612137575060008113155b1561216d57604051819083907f27f70c863f1bd3e335bb4d6bf2a31075c861752f0b21a03b816a356035b1dec690600090a35050565b6001546002546040805160c0810182528581526020810185815281830184815260608301868152600480546001600160801b0319608091821b8116828801908152600354600160401b900490921b811660a088019081529751632920706d60e21b815287519381019390935294516024830152925160448201529051606482015290518216608482015292511660a4830152906000908190819073542848e66d8f387a78717be7b39f7259b7782bae9063a481c1b49060c40160606040518083038186803b15801561223e57600080fd5b505af4158015612252573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061227691906128ad565b919450925090507f3a4a53e86baa9b577f931e849a3472fd6be844c0916377bc806be891847a5c2b6122a88784612b1d565b6122b28786612b1d565b6040805192835260208301919091520160405180910390a160028390556001829055600954600a546122f1916001600160a01b0391821691168361205b565b5050505050505050565b6000612350826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166123cd9092919063ffffffff16565b80519091501561186c578080602001905181019061236e919061269b565b61186c5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610623565b60606123dc84846000856123e6565b90505b9392505050565b6060824710156124475760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610623565b843b6124955760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610623565b600080866001600160a01b031685876040516124b1919061292d565b60006040518083038185875af1925050503d80600081146124ee576040519150601f19603f3d011682016040523d82523d6000602084013e6124f3565b606091505b509150915061250382828661250e565b979650505050505050565b6060831561251d5750816123df565b82511561252d5782518084602001fd5b8160405162461bcd60e51b815260040161062391906129ef565b82805461255390612b88565b90600052602060002090601f01602090048101928261257557600085556125bb565b82601f1061258e5782800160ff198235161785556125bb565b828001600101855582156125bb579182015b828111156125bb5782358255916020019190600101906125a0565b506125c79291506125e9565b5090565b60405180604001604052806002906020820280368337509192915050565b5b808211156125c757600081556001016125ea565b80356001600160a01b038116811461261557600080fd5b919050565b60006020828403121561262c57600080fd5b6123df826125fe565b60008060006060848603121561264a57600080fd5b612653846125fe565b9250612661602085016125fe565b9150604084013590509250925092565b6000806040838503121561268457600080fd5b61268d836125fe565b946020939093013593505050565b6000602082840312156126ad57600080fd5b815180151581146123df57600080fd5b6000602082840312156126cf57600080fd5b81516001600160801b0319811681146123df57600080fd5b6000602082840312156126f957600080fd5b5051919050565b6000806040838503121561271357600080fd5b82519150602083015167ffffffffffffffff8082111561273257600080fd5b818501915085601f83011261274657600080fd5b81518181111561275857612758612bef565b604051601f8201601f19908116603f0116810190838211818310171561278057612780612bef565b8160405282815288602084870101111561279957600080fd5b6127aa836020830160208801612b5c565b80955050505050509250929050565b600080604083850312156127cc57600080fd5b50508035926020909101359150565b6000602082840312156127ed57600080fd5b813567ffffffffffffffff81111561280457600080fd5b82016101c081850312156123df57600080fd5b60006020828403121561282957600080fd5b813561ffff811681146123df57600080fd5b60006020828403121561284d57600080fd5b5035919050565b6000806040838503121561286757600080fd5b505080516020909101519092909150565b60008060006060848603121561288d57600080fd5b83359250602084013591506128a4604085016125fe565b90509250925092565b6000806000606084860312156128c257600080fd5b8351925060208401519150604084015190509250925092565b6000602082840312156128ed57600080fd5b813563ffffffff811681146123df57600080fd5b60008151808452612919816020860160208601612b5c565b601f01601f19169290920160200192915050565b6000825161293f818460208701612b5c565b9190910192915050565b6001600160a01b03841681526040602082018190528101829052818360608301376000818301606090810191909152601f909201601f1916010192915050565b60408101818360005b60028110156129ba5781516001600160a01b0316835260209283019290910190600101612992565b50505092915050565b8481526080602082015260006129dc6080830186612901565b6040830194909452506060015292915050565b6020815260006123df6020830184612901565b6020808252600e908201526d141bdbdb081a5cc81c185d5cd95960921b604082015260600190565b6020808252601c908201527f6d73672e73656e646572206e6f7420706f6f6c436f6d6d697474657200000000604082015260600190565b60208082526019908201527f6d73672e73656e646572206e6f7420676f7665726e616e636500000000000000604082015260600190565b6000808335601e19843603018112612aaf57600080fd5b83018035915067ffffffffffffffff821115612aca57600080fd5b602001915036819003821315612adf57600080fd5b9250929050565b60008219821115612af957612af9612bc3565b500190565b6000816000190483118215151615612b1857612b18612bc3565b500290565b60008083128015600160ff1b850184121615612b3b57612b3b612bc3565b6001600160ff1b0384018313811615612b5657612b56612bc3565b50500390565b60005b83811015612b77578181015183820152602001612b5f565b838111156120f65750506000910152565b600181811c90821680612b9c57607f821691505b60208210811415612bbd57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fdfea264697066735822122069e0fd0f8969da041d0035e73ee854f756fe9bd42cda2186ad3cf2a3bfce859864736f6c634300080700330000000000000000000000000f79e82ae88e1318b8cfc8b4a205fe2f982b928a

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

0000000000000000000000000f79e82ae88e1318b8cfc8b4a205fe2f982b928a

-----Decoded View---------------
Arg [0] : _feeReceiver (address): 0x0f79e82ae88e1318b8cfc8b4a205fe2f982b928a

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000000f79e82ae88e1318b8cfc8b4a205fe2f982b928a


Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
Block Uncle Number Difficulty Gas Used Reward
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.