Contract 0xd974db6393b83274c7da596b5e9541503500d773 14

 
Txn Hash Method
Block
From
To
Value [Txn Fee]
0xb3c880ad6f0d31307798f884442d1d8d938d0c4c1be9bf618e8f65e2d178dd33Claim1853587572024-02-28 14:06:0682 days 20 hrs ago0xb833b1b0ef7f2b2183076868c18cf9a20661ac7e IN  0xd974db6393b83274c7da596b5e9541503500d7730 ETH0.00011807 0.1
0x118f6be8d694bc551d1c0cc0f7dccea82fad8694479e6951b36ef077e09b054bClaim1852088782024-02-28 3:34:2483 days 6 hrs ago0x8764ff06b1776cdca8456262c63d6a10d1ca0390 IN  0xd974db6393b83274c7da596b5e9541503500d7730 ETH0.00010146 0.1
0x05f876135611e8c56e84d0f37d5befb116a63a624351d658013d6aa7e237fb31Claim1803695452024-02-13 15:29:5597 days 18 hrs ago0x8f9be4310f9abb0e5843cc6363908c9b01dfeb3f IN  0xd974db6393b83274c7da596b5e9541503500d7730 ETH0.000113390.1
0xb23366eafa868a4650f03f40a3cb3198f269b230d84c9b4ec07ecbd26cd8c50aClaim1753902452024-01-29 13:00:17112 days 21 hrs ago0x4029c025dfbfbd8b47ce43284db36af22495d7b7 IN  0xd974db6393b83274c7da596b5e9541503500d7730 ETH0.00004352 0.1
0x909a510dc5520e456aca46b6eb388d135d8f1dcbf9099d598efa5d6d926c1f2aClaim1753900712024-01-29 12:59:33112 days 21 hrs ago0x4029c025dfbfbd8b47ce43284db36af22495d7b7 IN  0xd974db6393b83274c7da596b5e9541503500d7730 ETH0.00004523 0.1
0x88220daa3d2eef9eb418160f0e3b8d02d04b0ad33d616d568cae8070d890d90fClaim1645620022023-12-28 9:22:04145 days 52 mins ago0x9cbc96150f8dd62aab7f5f7a68128e21a4106018 IN  0xd974db6393b83274c7da596b5e9541503500d7730 ETH0.00007203 0.1
0x5149c5b0979b389c1f99fe5a29da953260108ee9e2e5d6ecb7a24cd846a82f84Claim1571128362023-12-05 12:43:18167 days 21 hrs ago0xe6cf807e4b2a640dfe03ff06fa6ab32c334c7df4 IN  0xd974db6393b83274c7da596b5e9541503500d7730 ETH0.00009962 0.1
0x5713278ac40aecf8965f4dfc23bb87c37b13fb9ee53e3c9fbf6ca8b9f0ce6dc3Claim1555981182023-11-30 16:28:52172 days 17 hrs ago0x98e01dab9167f9691dbf05c551d63533afb00566 IN  0xd974db6393b83274c7da596b5e9541503500d7730 ETH0.00011308 0.1
0x5e23a0df9cf0dbb2c031b1652d54276e4b3b0b904da359292fbb75b578bc10e4Claim1523958092023-11-20 21:01:52182 days 13 hrs ago0xca695144ed80d2e5f10c8938c08dffbf2516a170 IN  0xd974db6393b83274c7da596b5e9541503500d7730 ETH0.00005982 0.1
0x09e61b37a754a5b1f0cd05cfbd0f826a42549eaa6c0beb6196863f0eac612084Claim1508306742023-11-16 1:29:23187 days 8 hrs ago0xbf843f2aa6425952ae92760250503ce9930342b4 IN  0xd974db6393b83274c7da596b5e9541503500d7730 ETH0.00006254 0.1
0x9a305b964cf27222ad196b450e7a93c99b86a08017c252afaafd7e8d990eb782Claim1477452572023-11-06 16:08:13196 days 18 hrs ago0x26c9fc612b005781127246bbc5dc39f823e3106e IN  0xd974db6393b83274c7da596b5e9541503500d7730 ETH0.000082930.1
0x49265c52a1682837101c3302102882dab75310ca76fa27b438f449764e50abb0Claim1442130222023-10-26 14:41:38207 days 19 hrs ago0xdb47714727cba70f0408ba30dc4ea0b5ac436055 IN  0xd974db6393b83274c7da596b5e9541503500d7730 ETH0.0000524 0.15003
0xe5c8abd45aafabaf0591268ee6c2dd62b639af7ffaabc3c8453ff3df10ab9dccClaim1432249172023-10-23 13:41:14210 days 20 hrs ago0xef1bf3819dd59de69d6a7847eb6b70645adbec60 IN  0xd974db6393b83274c7da596b5e9541503500d7730 ETH0.000053410.1
0x630c8d790eacc936205d7ba8f47a02d5a8a6db2e3b2e220ddf7d0545bc0fa912Claim1432248962023-10-23 13:41:08210 days 20 hrs ago0xef1bf3819dd59de69d6a7847eb6b70645adbec60 IN  0xd974db6393b83274c7da596b5e9541503500d7730 ETH0.000055120.1
0x00de004474b441ffc4df2bde3617332866950d21a8b57a54556df87886b224a4Claim1381050272023-10-06 13:59:53227 days 20 hrs ago0xc0155194fb7c29b9828df197d4032ab0d29afb03 IN  0xd974db6393b83274c7da596b5e9541503500d7730 ETH0.00003394 0.1
0x770536dd13fb522944f3852184ab81804d0a8398d1d39602d5cdfd9def4a1ff2Claim1381049852023-10-06 13:59:42227 days 20 hrs ago0xc0155194fb7c29b9828df197d4032ab0d29afb03 IN  0xd974db6393b83274c7da596b5e9541503500d7730 ETH0.00003395 0.1
0xdeea4a6a9f98265c56831749f5432dc8b251ab5d6bd7acd5ae8bf35eeecf362cClaim1373892912023-10-04 10:00:11230 days 14 mins ago0xd119e0b221bd3707f0a62e59bb3c632fca21a134 IN  0xd974db6393b83274c7da596b5e9541503500d7730 ETH0.000027680.1
0xce28c997ef846b2d865e7f274c5d32024dd5c3178a2db87eaa2327dcff6dae87Distribute Profi...1370413162023-10-03 8:41:21231 days 1 hr ago0xa3f65e6247358cc9757299d77f68491ee154f535 IN  0xd974db6393b83274c7da596b5e9541503500d7730 ETH0.00002955 0.1
0x311c110ba3d61e470ea595399b8954ce50f12adfba15c0065736028f6c98ea11Close Position1370411002023-10-03 8:40:27231 days 1 hr ago0xa3f65e6247358cc9757299d77f68491ee154f535 IN  0xd974db6393b83274c7da596b5e9541503500d7730.00018 ETH0.00007387 0.1
0x7e566bb0359550802b5492dd68cad166554f772333594abecc59b8d5c207b02cCancel Order1370410132023-10-03 8:40:08231 days 1 hr ago0xa3f65e6247358cc9757299d77f68491ee154f535 IN  0xd974db6393b83274c7da596b5e9541503500d7730 ETH0.00003843 0.1
0x769db7e4b64a1283c33ad78770a7195a497ce2d5df0f897d9eec026cc9f9f36aClose Liquidated...1367022882023-10-02 7:44:35232 days 2 hrs ago0xa3f65e6247358cc9757299d77f68491ee154f535 IN  0xd974db6393b83274c7da596b5e9541503500d7730 ETH0.00001754 0.1
0x30218bb35d296dc3b6b5b5c914a0e4b3bf499093d3250df809d2973801190f5dClaim1365432502023-10-01 19:44:03232 days 14 hrs ago0x5e22f4c4dc429cb9e6f2cd8f78c338315a6e2e34 IN  0xd974db6393b83274c7da596b5e9541503500d7730 ETH0.000024490.1
0x7c83a02103a1685cd3ee9871910db57a1008aec8c87d41184d9e8f0af347df9dClaim1358109002023-09-29 15:12:13234 days 19 hrs ago0x0999033a70b936bd10582437040550eab875ca95 IN  0xd974db6393b83274c7da596b5e9541503500d7730 ETH0.000062190.1
0x635f6c5233525bbbdb5fa067959205ab518d4762741619c4d31905a55c631c3fClaim1351777482023-09-27 17:50:35236 days 16 hrs ago0x06cb95c96d87dc61a04377f3ed519006baa5ad8f IN  0xd974db6393b83274c7da596b5e9541503500d7730 ETH0.000043250.1
0x385a37ae3146930c82bbec54b651a38768079aab8e9583ef13d60a16de3c47ecClaim1351776422023-09-27 17:50:09236 days 16 hrs ago0xa136134b5a26e4446724f74763f95e51f42b2fce IN  0xd974db6393b83274c7da596b5e9541503500d7730 ETH0.000041480.1
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0x311c110ba3d61e470ea595399b8954ce50f12adfba15c0065736028f6c98ea111370411002023-10-03 8:40:27231 days 1 hr ago 0xd974db6393b83274c7da596b5e9541503500d773 0x99d43e82b98ccf211d214d541bc2b40961e43dd30.000180000000000001 ETH
0xe1cf624ee283796635d3ac566d2885029532d6c041e4c616bd375082f801d8421332281302023-09-21 15:35:29242 days 18 hrs ago 0xd974db6393b83274c7da596b5e9541503500d773 0xbc3b2d1cfc85276067d7aa1d38d6d6f2ee792d110.000180000000000001 ETH
0xa7c10ee64a04854ddd4d16249733fe154a88ac0d74bfef3672a008a4b16c92281322835022023-09-18 17:25:08245 days 16 hrs ago 0xd974db6393b83274c7da596b5e9541503500d773 0x486f5d90c66367c89b6c3bb67c4f4624998352540.000180000000000001 ETH
0x4e5b91e73949596754ae417b34bb9b19ad841c96640abaf37e6de5b0e0a6ba251322177452023-09-18 12:33:03245 days 21 hrs ago 0xd974db6393b83274c7da596b5e9541503500d773 0xbc87e990feb4c93094e06f1e5793ede6b4fc943a0.000180000000000001 ETH
0xd8cdd8ef37d510dd6a6ea701a2d17d60f90dcd944b1ad53aae24281bbe8a34d01307703762023-09-13 16:39:10250 days 17 hrs ago 0xd974db6393b83274c7da596b5e9541503500d773 0x924efca152039677b3513bd19ca5552f620b152a0.000180000000000001 ETH
0x6499271bec20dd5a844032187acfbbd5cfa1d8c44630261731554bd43bac8a151307321582023-09-13 13:48:40250 days 20 hrs ago 0xd974db6393b83274c7da596b5e9541503500d773 0x6abad7ff4e1a460069d10036d03c1c4d730167a70.000180000000000001 ETH
0x732721a2d03dab225347914e3b1e88089ae249a18f9e96e9a5759e71a4a358c71307023302023-09-13 11:35:58250 days 22 hrs ago 0xd974db6393b83274c7da596b5e9541503500d773 0x632dbdc374acf94eb978302c9c712a7ac476444e0.000180000000000001 ETH
0x3f329817c2a0018c681e2eee5cd29b13e3ba9f3cc9b02980013b6c9302a5e8c51304735102023-09-12 17:00:06251 days 17 hrs ago 0xd974db6393b83274c7da596b5e9541503500d773 0x2920f7932acc3fcd597eb4e09a892059bccdcdb10.000180000000000001 ETH
0xd7a34cfc9f8d79382e5b92a499ebad4ceaa54921069619be062221a3b982ea461304337792023-09-12 14:01:03251 days 20 hrs ago 0xd974db6393b83274c7da596b5e9541503500d773  Contract Creation0 ETH
0x9dab058fac40e2bc196af36e94bf8daec530ed1bb54696138eec609231924d041304241752023-09-12 13:19:42251 days 20 hrs ago 0xd974db6393b83274c7da596b5e9541503500d773  Contract Creation0 ETH
0x7e4460a38323eebe5dba2390e9d475718bd01df70c8e17076094a7570fb55e1c1304229132023-09-12 13:14:12251 days 21 hrs ago 0xd974db6393b83274c7da596b5e9541503500d773 0x229b93ecd068adc1e526b7c4a6c0760c745169330.000180000000000001 ETH
0x38c0ec9da7ee21f75b93913277370851ce98d1c5c374ea6e49f5dcd315fe27d81304148582023-09-12 12:39:21251 days 21 hrs ago 0xd974db6393b83274c7da596b5e9541503500d773 0x924efca152039677b3513bd19ca5552f620b152a0.00018 ETH
0x1a36038bce13c1e2ac49472ec75daeeb69f452c8b983ae3e175bc236124ee5cd1304144922023-09-12 12:37:49251 days 21 hrs ago 0xd974db6393b83274c7da596b5e9541503500d773  Contract Creation0 ETH
0x1dbb3f7a504787902d4fd945d8a9bcf97c885a25aa1b04411287810b2735f84d1304119452023-09-12 12:27:05251 days 21 hrs ago 0xd974db6393b83274c7da596b5e9541503500d773 0x408dc66684c118b14be4493b1fc9c450177e38530.00018 ETH
0x8d1ff800991ea25183725aacd120001b289ca267346c1d60979288c350c19ad21304042212023-09-12 11:54:13251 days 22 hrs ago 0xd974db6393b83274c7da596b5e9541503500d773  Contract Creation0 ETH
0x24698e7427056ec6a1d2131c152ad4b3a70519c5cc9277099fea646fd036e95e1304017012023-09-12 11:43:22251 days 22 hrs ago 0xd974db6393b83274c7da596b5e9541503500d773  Contract Creation0 ETH
0x478e8b014df64e1f7e74c2d44993eb83dc4cc5e823222f2d8c038febd0decc731304013762023-09-12 11:41:57251 days 22 hrs ago 0xd974db6393b83274c7da596b5e9541503500d773 0x2920f7932acc3fcd597eb4e09a892059bccdcdb10.000180000000000001 ETH
0xe5ffce339145228e26fff52efc549b1ef39729df47cf68b1375f9837fd6144491303965692023-09-12 11:20:59251 days 22 hrs ago 0xd974db6393b83274c7da596b5e9541503500d773 0x2920f7932acc3fcd597eb4e09a892059bccdcdb10.000180000000000001 ETH
0x4446f85252297fdb09cdaca7f46c254c2b5167eac821b7a5ea19aa8869fe508f1303853842023-09-12 10:32:43251 days 23 hrs ago 0xd974db6393b83274c7da596b5e9541503500d773  Contract Creation0 ETH
0x7bad457ab3029660f307603369d7b41f8bc14dc573026eb47dbc29c6995a0bc71303666842023-09-12 9:12:14252 days 1 hr ago 0xd974db6393b83274c7da596b5e9541503500d773 0x902517275b65663e6634b571b1bba002b76ef0150.000180000000000001 ETH
0x5e484be6445d7a95927d5c16e3207fcbf42695836663f293a34a9e23d0bc0ca81303193882023-09-12 5:43:26252 days 4 hrs ago 0xd974db6393b83274c7da596b5e9541503500d773 0x229b93ecd068adc1e526b7c4a6c0760c745169330.00018 ETH
0xff16ab1935e2dff58690ad2be86523fb38ba2f95074710610537483c866d1cbd1302600252023-09-12 0:58:57252 days 9 hrs ago 0xd974db6393b83274c7da596b5e9541503500d773 0xdccfd74c1cbce07f44a7513c92c66540820b9bfe0.000180000000000001 ETH
0x2b14a2284db2e91d5bb0ee935835a64288f5566321c9dca958ba5c05f17119e81302596372023-09-12 0:56:58252 days 9 hrs ago 0xd974db6393b83274c7da596b5e9541503500d773 0xdccfd74c1cbce07f44a7513c92c66540820b9bfe0.000180000000000001 ETH
0x2601f9c9d82d16c45f2e0f0a9e4a7392061e8c9be4da94d4b65eec39999e5bcf1302570202023-09-12 0:44:55252 days 9 hrs ago 0xd974db6393b83274c7da596b5e9541503500d773 0x5d6b5531e112daff1adfb115869f4534c09f61b20.000180000000000001 ETH
0x377c261615e36c9702c4475927e72372527ff2e7cf5ee75d016d1ee8a55ec8041302522882023-09-12 0:18:49252 days 9 hrs ago 0xd974db6393b83274c7da596b5e9541503500d773 0xdccfd74c1cbce07f44a7513c92c66540820b9bfe0.000180000000000001 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:
StfxVault

Compiler Version
v0.8.15+commit.e14f2714

Optimization Enabled:
Yes with 10000 runs

Other Settings:
default evmVersion
File 1 of 34 : IStfxGmx.sol
//SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import {IStfxStorage} from "src/interfaces/IStfxStorage.sol";

interface IStfxGmx is IStfxStorage {
    event FundDeadlineChanged(uint256 newDeadline, address indexed stfxAddress);
    event ManagerAddressChanged(address indexed newManager, address indexed stfxAddress);
    event ReferralCodeChanged(bytes32 newReferralCode, address indexed stfxAddress);
    event ClaimedUSDC(address indexed investor, uint256 claimAmount, uint256 timeOfClaim, address indexed stfxAddress);
    event VaultLiquidated(uint256 timeOfLiquidation, address indexed stfxAddress);
    event NoFillVaultClosed(uint256 timeOfClose, address indexed stfxAddress);
    event TradeDeadlineChanged(uint256 newTradeDeadline, address indexed stfxAddress);

    function getStf() external view returns (Stf memory);

    function openPosition(bool _isLimit, uint256 _triggerPrice, uint256 _totalRaised) external payable;

    function closePosition(bool _isLimit, uint256 _size, uint256 _triggerPrice, bool _triggerAboveThreshold)
        external
        payable
        returns (bool);

    function distributeProfits() external returns (uint256, uint256, uint256);

    function cancelOrder(uint256 _orderIndex, bool _isOpen) external returns (uint256);

    function withdraw(address receiver, bool isEth, address token, uint256 amount) external;
}

File 2 of 34 : IStfxStorage.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

interface IStfxStorage {
    /// @notice Enum to describe the trading status of the vault
    /// @dev NOT_OPENED - Not open
    /// @dev OPENED - opened position
    /// @dev CLOSED - closed position
    /// @dev LIQUIDATED - liquidated position
    /// @dev CANCELLED - did not start due to deadline reached
    /// @dev DISTRIBUTED - distributed fees
    enum StfStatus {
        NOT_OPENED,
        OPENED,
        CLOSED,
        LIQUIDATED,
        CANCELLED,
        DISTRIBUTED
    }

    struct Dex {
        address vault;
        address marketRegistry;
        address clearingHouse;
    }

    struct Stf {
        address baseToken;
        bool tradeDirection;
        uint256 fundraisingPeriod;
        uint256 entryPrice;
        uint256 targetPrice;
        uint256 liquidationPrice;
        uint256 leverage;
    }

    struct StfInfo {
        address stfxAddress;
        address manager;
        uint256 totalRaised;
        uint256 remainingAmountAfterClose;
        uint256 endTime;
        uint256 fundDeadline;
        StfStatus status;
        mapping(address => uint256) userAmount;
        mapping(address => uint256) claimAmount;
        mapping(address => bool) claimed;
    }
}

File 3 of 34 : StfxVault.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.15;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IStfx} from "src/interfaces/IStfx.sol";
import {IStfxPerp} from "src/perp/interfaces/IStfxPerp.sol";
import {IStfxGmx} from "src/gmx/interfaces/IStfxGmx.sol";
import {IGmxVault} from "src/interfaces/external/gmx/IGmxVault.sol";
import {IStfxVault} from "./interfaces/IStfxVault.sol";
import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol";
import {Pausable} from "@openzeppelin/contracts/security/Pausable.sol";
import {IReader} from "src/interfaces/IReader.sol";

error ZeroAddress();
error ZeroAmount();
error ZeroTokenBalance();
error NoAccess(address desired, address given);
error StillFundraising(uint256 desired, uint256 given);
error InvalidChainId(uint256 desired, uint256 given);
error BelowMin(uint256 min, uint256 given);
error AboveMax(uint256 max, uint256 given);

error FundExists(address fund);
error NoBaseToken(address token);
/// Direction: 0 = long, 1 = short.
error NotEligible(uint256 entry, uint256 exit, bool direction);
error AlreadyOpened();
error MismatchStatus(IStfxVault.StfStatus given);
error CantOpen();
error CantClose();
error NotOpened();
error NotFinalised();
error NoCloseActions();
error OpenPosition();
error NoOpenPositions();

/// @title StfxVault
/// @author 7811, abhi3700
/// @notice Contract for the investors to deposit and for managers to open and close positions
contract StfxVault is IStfxVault, Pausable {
    /*//////////////////////////////////////////////////////////////
                            STATE VARIABLES
    //////////////////////////////////////////////////////////////*/

    // usdc address
    address private USDC;
    // weth address
    address private WETH;

    // owner/deployer of the contract
    // used for setting and updating the logic changes
    address public owner;
    // address used by the backend bot to close/cancel the stfs
    address public admin;
    // address used to collect the protocol fees
    address public treasury;
    // implementation of the `Stfx` contract
    address public stfxImplementation;

    IReader public reader;

    // max amount which can be fundraised by the manager per stf
    uint256 public capacityPerStf;
    // min investment amount per investor per stf
    uint256 public minInvestmentAmount;
    // max investment amount per investor per stf
    uint256 public maxInvestmentAmount;
    // percentage of fees from the profits of the stf to the manager (default - 15e18 (15%))
    uint256 public managerFee;
    // percentage of fees from the profits of the stf to the protocol (default - 5e18 (5%))
    uint256 public protocolFee;
    // max leverage which can be used by the manager when creating an stf
    uint256 public maxLeverage;
    // min leverage which can be used by the manager when creating an stf
    uint256 public minLeverage;
    // max fundraising period which can be used by the manager to raise funds (defaults - 1 week)
    uint256 public maxFundraisingPeriod;
    // the max time a trade can be open, default - 30 days
    uint256 public maxDeadlineForPosition;
    // referralCode used for opening a position on the dex
    bytes32 public referralCode;

    mapping(address => StfInfo) public stfInfo;
    // manager's address to indicate if the manager is managing a fund currently
    // manager can only manage one stf per address
    mapping(address => bool) public isManagingFund;
    // stf address to the actual amount raised before swaps for cancel order
    // will be used to calculate `utilizationRatio` when using partial amount for opening a position
    mapping(address => uint256) public actualTotalRaised;
    // mapping of stf and the manager fees
    mapping(address => uint256) public managerFees;
    // mapping of stf and the protocol fees 
    mapping(address => uint256) public protocolFees;

    /*//////////////////////////////////////////////////////////////
                            INITIALIZE
    //////////////////////////////////////////////////////////////*/

    /// @notice initializing state variables in the contructor
    /// @dev require checks to make sure the addresses are not zero addresses
    /// @param _reader `Reader` contract address
    /// @param _stfxImplementation `Stfx` contract address
    /// @param _capacityPerStf max amount which can be fundraised by the manager per stf
    /// @param _minInvestmentAmount min investment amount per investor per stf
    /// @param _maxInvestmentAmount max investment amount per investor per stf
    /// @param _maxLeverage max leverage which can be used by the manager when creating an stf
    /// @param _usdc USDC contract address
    /// @param _weth WETH contract address
    /// @param _admin address used by the bot to close/cancel Stfs
    /// @param _treasury address used to collect protocol fees
    constructor(
        address _reader,
        address _stfxImplementation,
        uint256 _capacityPerStf,
        uint256 _minInvestmentAmount,
        uint256 _maxInvestmentAmount,
        uint256 _maxLeverage,
        address _usdc,
        address _weth,
        address _admin,
        address _treasury
    ) {
        if (_reader == address(0)) revert ZeroAddress();
        if (_stfxImplementation == address(0)) revert ZeroAddress();
        if (_usdc == address(0)) revert ZeroAddress();
        if (_weth == address(0)) revert ZeroAddress();
        if (_admin == address(0)) revert ZeroAddress();
        if (_treasury == address(0)) revert ZeroAddress();
        reader = IReader(_reader);
        owner = msg.sender;
        stfxImplementation = _stfxImplementation;
        capacityPerStf = _capacityPerStf;
        minInvestmentAmount = _minInvestmentAmount;
        maxInvestmentAmount = _maxInvestmentAmount;
        minLeverage = 1e6;
        maxLeverage = _maxLeverage;
        USDC = _usdc;
        WETH = _weth;
        managerFee = 15e18;
        protocolFee = 5e18;
        maxFundraisingPeriod = 1 weeks;
        admin = _admin;
        treasury = _treasury;
        maxDeadlineForPosition = 2592000; // 30 days

        emit InitializedVault(
            _reader,
            _stfxImplementation,
            _capacityPerStf,
            _minInvestmentAmount,
            _maxInvestmentAmount,
            _maxLeverage,
            _usdc,
            _weth,
            _admin,
            _treasury
            );
    }

    /*//////////////////////////////////////////////////////////////
                              MODIFIERS
    //////////////////////////////////////////////////////////////*/

    /// @notice modifier for the setters to be called only by the manager
    modifier onlyOwner() {
        if (msg.sender != owner) revert NoAccess(owner, msg.sender);
        _;
    }

    /// @notice modifier for cancel vaults to be called only by the admin
    modifier onlyAdmin() {
        if (msg.sender != admin) revert NoAccess(admin, msg.sender);
        _;
    }

    /*//////////////////////////////////////////////////////////////
                              VIEW
    //////////////////////////////////////////////////////////////*/

    // TODO (should we move view functions to Reader?)
    function getUserAmount(address _stfxAddress, address _investor) external view override returns (uint256) {
        StfInfo storage _stf = stfInfo[_stfxAddress];
        return _stf.userAmount[_investor];
    }

    function getClaimAmount(address _stfxAddress, address _investor) external view override returns (uint256) {
        StfInfo storage _stf = stfInfo[_stfxAddress];
        return _stf.claimAmount[_investor];
    }

    function getClaimed(address _stfxAddress, address _investor) external view override returns (bool) {
        StfInfo storage _stf = stfInfo[_stfxAddress];
        return _stf.claimed[_investor];
    }

    function getStfInfo(address _stfxAddress)
        external
        view
        returns (address, address, uint256, uint256, uint256, uint256, StfStatus)
    {
        StfInfo storage _stf = stfInfo[_stfxAddress];
        return (
            _stf.stfxAddress,
            _stf.manager,
            _stf.totalRaised,
            _stf.remainingAmountAfterClose,
            _stf.endTime,
            _stf.fundDeadline,
            _stf.status
        );
    }

    function getPosition(address _stfxAddress)
        public
        view
        returns (
            uint256 size,
            uint256 collateral,
            uint256 price,
            uint256 entryFundingRate,
            uint256 reserveAmount,
            uint256 realisedPnl,
            bool isProfit
        )
    {
        Stf memory _stf = IStfxGmx(_stfxAddress).getStf();
        address _dex = reader.getDex()[0];

        {
            (size, collateral, price, entryFundingRate, reserveAmount, realisedPnl, isProfit,) = IGmxVault(_dex)
                .getPosition(_stfxAddress, _stf.tradeDirection ? _stf.baseToken : USDC, _stf.baseToken, _stf.tradeDirection);
        }
    }

    function shouldDistribute(address _stfxAddress) external view returns (bool) {
        StfInfo storage _stf = stfInfo[_stfxAddress];
        (uint256 _size,,,,,,) = getPosition(_stfxAddress);
        if (_stf.status == StfStatus.CLOSED && _size == 0) {
            return true;
        }
        return false;
    }

    function shouldCancelOpenLimitOrder(address _stfxAddress) public view returns (bool) {
        StfInfo storage _stf = stfInfo[_stfxAddress];
        (uint256 _size,,,,,,) = getPosition(_stfxAddress);
        if (_stf.status == StfStatus.OPENED && _size == 0 && block.timestamp > _stf.endTime + _stf.fundDeadline) {
            return true;
        }
        return false;
    }

    function isDistributed(address _stfxAddress) external view returns (bool) {
        StfInfo storage _stf = stfInfo[_stfxAddress];
        if(_stf.status == StfStatus.DISTRIBUTED) return true;
    }

    function isClosed(address _stfxAddress) external view returns (bool) {
        StfInfo storage _stf = stfInfo[_stfxAddress];
        if(_stf.status == StfStatus.CLOSED) return true;
    }

    function isOpened(address _stfxAddress) external view returns (bool) {
        StfInfo storage _stf = stfInfo[_stfxAddress];
        if(_stf.status == StfStatus.OPENED) return true;
    }

    function isCancelled(address _stfxAddress) external view returns (bool) {
        StfInfo storage _stf = stfInfo[_stfxAddress];
        if(_stf.status == StfStatus.CANCELLED) return true;
    }

    function isNotOpened(address _stfxAddress) external view returns (bool) {
        StfInfo storage _stf = stfInfo[_stfxAddress];
        if(_stf.status == StfStatus.NOT_OPENED) return true;
    }

    function isLiquidated(address _stfxAddress) external view returns (bool) {
        StfInfo storage _stf = stfInfo[_stfxAddress];
        if(_stf.status == StfStatus.LIQUIDATED) return true;
    }

    function getStatusOfStf(address _stfxAddress) external view returns (StfStatus) {
        StfInfo storage _stf = stfInfo[_stfxAddress];
        return _stf.status;
    }

    function getPnl(address _stfxAddress) 
        external 
        view 
        returns (
            uint256 mFee, 
            uint256 pFee, 
            int256 pnlBeforeFees,
            int256 pnlAfterFees, 
            bool isDistributed
        ) 
    {   
        StfInfo storage _stf = stfInfo[_stfxAddress];
        if (_stf.status == StfStatus.DISTRIBUTED) isDistributed = true;
        mFee = managerFees[_stfxAddress];
        pFee = protocolFees[_stfxAddress];
        pnlBeforeFees = int256(_stf.remainingAmountAfterClose + mFee + pFee) - int256(actualTotalRaised[_stfxAddress]);
        pnlAfterFees = int256(_stf.remainingAmountAfterClose) - int256(actualTotalRaised[_stfxAddress]);
    }

    /*//////////////////////////////////////////////////////////////
                          EXTERNAL FUNCTIONS
    //////////////////////////////////////////////////////////////*/

    /// @notice Create a new Single Trade Fund (STF)
    /// @dev returns the address of the proxy contract with Stfx.sol implementation
    /// @param _stf the fund details, check `IStfxStorage.Stf`
    /// @return stfxAddress address of the proxy contract which is deployed
    function createNewStf(Stf calldata _stf) external override whenNotPaused returns (address stfxAddress) {
        if (isManagingFund[msg.sender]) revert FundExists(msg.sender);
        if (_stf.fundraisingPeriod < 15 minutes) revert BelowMin(15 minutes, _stf.fundraisingPeriod);
        if (_stf.fundraisingPeriod > maxFundraisingPeriod) {
            revert AboveMax(maxFundraisingPeriod, _stf.fundraisingPeriod);
        }
        if (_stf.leverage < minLeverage) revert BelowMin(minLeverage, _stf.leverage);
        if (_stf.leverage > maxLeverage) revert AboveMax(maxLeverage, _stf.leverage);
        // checks the dex if the token is eligible for opening a position
        if (!reader.getBaseTokenEligible(_stf.baseToken)) revert NoBaseToken(_stf.baseToken);
        // checks if the entry and the target price are eligible (0.1x - 10x of the currentPrice)
        if (!reader.checkPrices(_stf.entryPrice, _stf.targetPrice, _stf.baseToken, _stf.tradeDirection)) {
            revert NotEligible(_stf.entryPrice, _stf.targetPrice, _stf.tradeDirection);
        }

        stfxAddress = Clones.clone(stfxImplementation);
        IStfx(stfxAddress).initialize(_stf, msg.sender, USDC, WETH, address(reader));

        stfInfo[stfxAddress].stfxAddress = stfxAddress;
        stfInfo[stfxAddress].manager = msg.sender;
        stfInfo[stfxAddress].endTime = block.timestamp + _stf.fundraisingPeriod;
        stfInfo[stfxAddress].fundDeadline = 72 hours;
        isManagingFund[msg.sender] = true;

        emit NewFundCreated(
            _stf.baseToken,
            _stf.fundraisingPeriod,
            _stf.entryPrice,
            _stf.targetPrice,
            _stf.liquidationPrice,
            _stf.leverage,
            _stf.tradeDirection,
            stfxAddress,
            msg.sender
            );
    }

    /// @notice deposit a particular amount into an stf for the manager to open a position
    /// @dev `fundraisingPeriod` has to end and the `totalRaised` should not be more than `maxInvestmentPerStf`
    /// @dev amount has to be between `minInvestmentAmount` and `maxInvestmentAmount`
    /// @dev approve has to be called before this method for the investor to transfer usdc to this contract
    /// @param _stfxAddress address of the stf the investor wants to invest
    /// @param amount amount the investor wants to deposit
    function depositIntoFund(address _stfxAddress, uint256 amount) external override whenNotPaused {
        StfInfo storage _stf = stfInfo[_stfxAddress];
        if (block.timestamp > _stf.endTime) revert AboveMax(_stf.endTime, block.timestamp);
        if (amount < minInvestmentAmount) revert BelowMin(minInvestmentAmount, amount);
        if (_stf.userAmount[msg.sender] + amount > maxInvestmentAmount) {
            revert AboveMax(maxInvestmentAmount, _stf.userAmount[msg.sender] + amount);
        }
        if (_stf.status != StfStatus.NOT_OPENED) revert AlreadyOpened();
        if (_stf.totalRaised + amount > capacityPerStf) revert AboveMax(capacityPerStf, _stf.totalRaised + amount);

        _stf.totalRaised += amount;
        _stf.userAmount[msg.sender] += amount;
        actualTotalRaised[_stfxAddress] += amount;

        IERC20(USDC).transferFrom(msg.sender, address(this), amount);
        emit DepositIntoFund(_stfxAddress, msg.sender, amount);
    }

    /// @notice allows the manager to close the fundraising and open a position later
    /// @dev changes the `_stf.endTime` to the current `block.timestamp`
    /// @param _stfxAddress address of the stf where the manager wants to close fundraising
    function closeFundraising(address _stfxAddress) external override whenNotPaused {
        StfInfo storage _stf = stfInfo[_stfxAddress];
        if (_stf.manager != msg.sender) revert NoAccess(_stf.manager, msg.sender);
        if (_stf.status != StfStatus.NOT_OPENED) revert AlreadyOpened();
        if (_stf.totalRaised < 1) revert ZeroAmount();
        if (block.timestamp >= _stf.endTime) revert CantClose();

        _stf.endTime = block.timestamp;

        emit FundraisingClosed(_stfxAddress);
    } 

    /// @notice allows the manager to end the `fundraisingPeriod` early and open a market position
    /// @dev transfers the `totalRaised` usdc of the `stfxAddress` to the `Stfx` contract
    /// @param _stfxAddress address of the stf the manager wants to open a market position early
    /// @param _isLimit if true, then its a limit order, else a market order
    /// @param _triggerPrice price input depending on the latest price from the dex
    function closeFundraisingAndOpenPosition(address _stfxAddress, bool _isLimit, uint256 _triggerPrice)
        external
        payable
        override
        whenNotPaused
    {
        StfInfo storage _stf = stfInfo[_stfxAddress];
        if (_stf.manager != msg.sender) revert NoAccess(_stf.manager, msg.sender);
        if (_stf.status != StfStatus.NOT_OPENED) revert AlreadyOpened();
        if (block.timestamp >= _stf.endTime) revert CantClose();
        if (_stf.totalRaised < 1) revert ZeroAmount();

        // update state variables
        _stf.status = StfStatus.OPENED;
        _stf.endTime = block.timestamp;

        // transfer first and then call `openPosition()`
        IERC20(USDC).transfer(_stfxAddress, _stf.totalRaised);

        if (block.chainid == 42161) {
            IStfxGmx(_stfxAddress).openPosition{value: msg.value}(_isLimit, _triggerPrice, _stf.totalRaised);
        } else if (block.chainid == 10) {
            if (!IStfxPerp(_stfxAddress).openPosition()) revert CantOpen();
        }

        emit FundraisingCloseAndVaultOpened(_stfxAddress, _isLimit, _triggerPrice);
    }

    /// @notice allows the manager to open a limit or a market order
    /// @dev can be called only after the `fundraisingPeriod` is over
    /// @param _stfxAddress address of the stf. the manager wants to open an order
    /// @param _isLimit if true, then its a limit order, else a market order
    /// @param _triggerPrice price input depending on the latest price from the dex and whether its a limit or a market order
    function openPosition(address _stfxAddress, bool _isLimit, uint256 _triggerPrice)
        external
        payable
        override
        whenNotPaused
    {
        StfInfo storage _stf = stfInfo[_stfxAddress];
        if (msg.sender != _stf.manager) revert NoAccess(_stf.manager, msg.sender);
        if (_stf.endTime > block.timestamp) revert StillFundraising(_stf.endTime, block.timestamp);
        if (_stf.status != StfStatus.NOT_OPENED) revert AlreadyOpened();
        if (_stf.totalRaised < 1) revert ZeroAmount();

        _stf.status = StfStatus.OPENED;

        // transfer first and then call `openPosition()`
        IERC20(USDC).transfer(_stfxAddress, _stf.totalRaised);

        if (block.chainid == 42161) {
            IStfxGmx(_stfxAddress).openPosition{value: msg.value}(_isLimit, _triggerPrice, _stf.totalRaised);
        } else if (block.chainid == 10) {
            if (!IStfxPerp(_stfxAddress).openPosition()) revert CantOpen();
        }

        emit VaultOpened(_stfxAddress, _isLimit, _triggerPrice);
    }

    /// @notice allows the manager to close a limit or a market order
    /// @dev can be called only if theres a position already open
    /// @dev `stf.status` will be `CLOSED` and `isManagingFund(manager)` will be `false` only when the entire position size is closed
    /// @param _stfxAddress address of the stf, the manager wants to close the existing position
    /// @param _isLimit if true, then its a limit order, else a market order
    /// @param _size the position size which the manager wants to close
    /// @param _triggerPrice price input depending on the latest price from the dex and whether its a limit or a market order
    /// @param _triggerAboveThreshold bool to check if the `triggerPrice` is above or below the `currentPrice`, used for SL/TP
    function closePosition(
        address _stfxAddress,
        bool _isLimit,
        uint256 _size,
        uint256 _triggerPrice,
        bool _triggerAboveThreshold
    ) external payable override whenNotPaused {
        StfInfo storage _stf = stfInfo[_stfxAddress];
        (uint256 size,,,,,,) = getPosition(_stfxAddress);
        if (msg.sender != _stf.manager && msg.sender != admin) revert NoAccess(_stf.manager, msg.sender);
        if (_stf.status != StfStatus.OPENED) revert NoOpenPositions();
        if (_size != size) revert CantClose();

        bool closed;
        if (block.chainid == 42161) {
            closed = IStfxGmx(_stfxAddress).closePosition{value: msg.value}(
                _isLimit, _size, _triggerPrice, _triggerAboveThreshold
            );
        } else if (block.chainid == 10) {
            if (!IStfxPerp(_stfxAddress).closePosition()) revert CantClose();
        }

        if (closed) {
            _stf.status = StfStatus.CLOSED;
        }

        emit VaultClosed(_stfxAddress, _size, _isLimit, _triggerPrice, closed);
    }

    /// @notice allows the manager to cancel an order
    /// @dev checks if an order exists, will revert from the dex if an order has already been executed
    /// @param _stfxAddress address of the stf, the manager wants to cancel the existing order
    /// @param _orderIndex the order index from the dex
    /// @param _isOpen if true, the manager can cancel an open order, else, the manager can cancel a close order
    function cancelOrder(address _stfxAddress, uint256 _orderIndex, bool _isOpen) external override whenNotPaused {
        StfInfo storage _stf = stfInfo[_stfxAddress];
        if (msg.sender != _stf.manager && msg.sender != admin) revert NoAccess(_stf.manager, msg.sender);

        if (_isOpen) {
            if (_stf.status != StfStatus.OPENED) revert AlreadyOpened();
            _stf.status = StfStatus.NOT_OPENED;
            uint256 remainingBalance = IStfxGmx(_stfxAddress).cancelOrder(_orderIndex, _isOpen);
            _stf.totalRaised = remainingBalance;
        } else {
            if (_stf.status != StfStatus.OPENED && _stf.status != StfStatus.CLOSED) revert NoCloseActions();
            _stf.status = StfStatus.OPENED;
            isManagingFund[_stf.manager] = true;
            IStfxGmx(_stfxAddress).cancelOrder(_orderIndex, _isOpen);
        }

        emit OrderCancelled(_stfxAddress, _orderIndex, _isOpen, _stf.totalRaised);
    }

    /// @notice allows the manager create a position again in case the position does not get executed by the dex
    /// @dev `stf.status` will be `CLOSED` and `isManagingFund(manager)` will be `false` only when the entire position size is closed
    /// @param _stfxAddress address of the stf, the manager wants to create a position again
    /// @param _isLimit if true, then its a limit order, else a market order
    /// @param _isOpen if true, the manager can create an open position, else, the manager can create a close position
    /// @param _size the position size which the manager wants to close
    /// @param _triggerPrice price input depending on the latest price from the dex and whether its a limit or a market order
    /// @param _triggerAboveThreshold bool to check if the `triggerPrice` is above or below the `currentPrice`, used for SL/TP
    function createPositionAgain(
        address _stfxAddress,
        bool _isLimit,
        bool _isOpen,
        uint256 _size,
        uint256 _triggerPrice,
        bool _triggerAboveThreshold
    ) external payable override whenNotPaused {
        StfInfo storage _stf = stfInfo[_stfxAddress];
        if (msg.sender != _stf.manager) revert NoAccess(_stf.manager, msg.sender);

        if (_isOpen) {
            if (_stf.status != StfStatus.OPENED) revert AlreadyOpened();
            if (IERC20(USDC).balanceOf(_stfxAddress) < 1) revert ZeroTokenBalance();
            IStfxGmx(_stfxAddress).openPosition{value: msg.value}(_isLimit, _triggerPrice, _stf.totalRaised);
        } else {
            if (_stf.status != StfStatus.OPENED && _stf.status != StfStatus.CLOSED) revert NoCloseActions();
            bool closed = IStfxGmx(_stfxAddress).closePosition{value: msg.value}(
                _isLimit, _size, _triggerPrice, _triggerAboveThreshold
            );
            if (closed) {
                _stf.status = StfStatus.CLOSED;
            }
        }

        emit CreatedPositionAgain(_stfxAddress, _isOpen, _triggerPrice);
    }

    /// @notice allows the stf contract to transfer back the collateral received from the dex after closing the position
    /// @notice also transfers the fees in case of a profit to the manager and the protocol
    /// @dev is called immediately after the stf's position has been closed completely on the dex
    /// @dev can be called by the `owner` of this contract or by the stf's `manager`
    /// @param _stfxAddress address of the stf
    function distributeProfits(address _stfxAddress) external override whenNotPaused {
        if (block.chainid != 42161) revert InvalidChainId(42161, block.chainid);
        StfInfo storage _stf = stfInfo[_stfxAddress];
        if (msg.sender != _stf.manager && msg.sender != admin) revert NoAccess(_stf.manager, msg.sender);
        if (_stf.status != StfStatus.CLOSED) revert NotFinalised();

        (uint256 _remainingBalance, uint256 _managerFee, uint256 _protocolFee) =
            IStfxGmx(_stfxAddress).distributeProfits();
        _stf.remainingAmountAfterClose = _remainingBalance;
        _stf.status = StfStatus.DISTRIBUTED;
        isManagingFund[_stf.manager] = false;
        managerFees[_stfxAddress] = _managerFee;
        protocolFees[_stfxAddress] = _protocolFee;

        emit FeesTransferred(_stfxAddress, _remainingBalance, _managerFee, _protocolFee);
    }

    /// @notice get the `claimableAmount` of the investor from a particular stf
    /// @dev if theres no position opened, it'll return the deposited amount
    /// @dev after the position is closed, it'll calculate the `claimableAmount` depending on the weightage of the investor
    /// @param _stfxAddress address of the stf
    /// @param _investor address of the investor
    /// @return amount which can be claimed by the investor from a particular stf
    function claimableAmount(address _stfxAddress, address _investor) public view override returns (uint256 amount) {
        StfInfo storage _stf = stfInfo[_stfxAddress];

        if (_stf.claimed[_investor] || _stf.status == StfStatus.OPENED) {
            amount = 0;
        } else if (_stf.status == StfStatus.CANCELLED || _stf.status == StfStatus.NOT_OPENED) {
            amount = (_stf.totalRaised * _stf.userAmount[_investor] * 1e18) / (actualTotalRaised[_stfxAddress] * 1e18);
        } else if (_stf.status == StfStatus.DISTRIBUTED) {
            amount = (_stf.remainingAmountAfterClose * _stf.userAmount[_investor] * 1e18) / (actualTotalRaised[_stfxAddress] * 1e18);
        } else {
            amount = 0;
        }
    }

    /// @notice transfers the collateral to the investor depending on the investor's weightage to the totalRaised by the stf
    /// @dev will revert if the investor did not invest in the stf during the fundraisingPeriod
    /// @param _stfxAddress address of the invested stf
    function claim(address _stfxAddress) external override whenNotPaused {
        StfInfo storage _stf = stfInfo[_stfxAddress];
        if (_stf.status != StfStatus.DISTRIBUTED && _stf.status != StfStatus.CANCELLED) revert NotFinalised();

        uint256 amount = claimableAmount(_stfxAddress, msg.sender);
        if (amount < 1) revert ZeroTokenBalance();

        _stf.claimed[msg.sender] = true;
        _stf.claimAmount[msg.sender] = amount;

        IERC20(USDC).transfer(msg.sender, amount);
        emit Claimed(msg.sender, _stfxAddress, amount);
    }

    /*//////////////////////////////////////////////////////////////
                            ADMIN FUNCTIONS
    //////////////////////////////////////////////////////////////*/

    /// @notice will change the status of the stf to `LIQUIDATED` and `isManagingFund(manager)` to false
    /// @dev can be called once an stf is liquidated from the dex
    /// @dev can only be called by the `owner`
    /// @param _stfxAddress address of the stf
    function closeLiquidatedVault(address _stfxAddress) external override onlyAdmin whenNotPaused {
        StfInfo storage _stf = stfInfo[_stfxAddress];
        if (_stf.status != StfStatus.OPENED) revert NotOpened();
        _stf.status = StfStatus.LIQUIDATED;
        isManagingFund[_stf.manager] = false;
        emit VaultLiquidated(_stfxAddress);
    }

    /// @notice will change the status of the stf to `CANCELLED` and `isManagingFund(manager)` to false
    /// @dev can be called if there was nothing raised during `fundraisingPeriod`
    /// @dev or can be called if the manager did not open any position within the `fundDeadline` (default - 72 hours)
    /// @dev can only be called by the `owner`
    /// @param _stfxAddress address of the stf
    function cancelVault(address _stfxAddress) external override onlyAdmin whenNotPaused {
        StfInfo storage _stf = stfInfo[_stfxAddress];
        if (_stf.status != StfStatus.NOT_OPENED) revert OpenPosition();
        if (_stf.totalRaised == 0) {
            if (block.timestamp <= _stf.endTime) revert BelowMin(_stf.endTime, block.timestamp);
        } else {
            if (block.timestamp <= _stf.endTime + _stf.fundDeadline) revert BelowMin(_stf.endTime, block.timestamp);
        }
        _stf.status = StfStatus.CANCELLED;
        isManagingFund[_stf.manager] = false;
        emit NoFillVaultClosed(_stfxAddress);
    }

    /// @notice the manager can cancel the stf if they want, after fundraising
    /// @dev can be called by the `manager`
    /// @param _stfxAddress address of the stf
    function cancelStfByManager(address _stfxAddress) external override whenNotPaused {
        StfInfo storage _stf = stfInfo[_stfxAddress];
        if (msg.sender != _stf.manager) revert NoAccess(_stf.manager, msg.sender);
        if (_stf.status != StfStatus.NOT_OPENED) revert OpenPosition();
        if (block.timestamp > _stf.endTime + _stf.fundDeadline) revert CantClose();

        _stf.fundDeadline = 0;
        _stf.endTime = 0;
        _stf.status = StfStatus.CANCELLED;
        isManagingFund[_stf.manager] = false;
        emit NoFillVaultClosed(_stfxAddress);
    }

    /// @notice cancel an open limit order if not executed within `fundDeadline` (72 hours)
    /// @dev can be called by the `manager` and by the `admin`, will check if there's an open limit order created and cancel it
    /// @param _stfxAddress address of the stf
    /// @param _orderIndex the order index from the dex
    function cancelStfAfterOpening(address _stfxAddress, uint256 _orderIndex) external override whenNotPaused {
        StfInfo storage _stf = stfInfo[_stfxAddress];
        if(msg.sender != _stf.manager && msg.sender != admin) revert NoAccess(_stf.manager, msg.sender);

        if(msg.sender == admin) {
            if (block.timestamp <= _stf.endTime + _stf.fundDeadline) revert CantClose();
        }

        _stf.fundDeadline = 0;
        if(!shouldCancelOpenLimitOrder(_stfxAddress)) revert CantClose();
        uint256 remainingBalance = IStfxGmx(_stfxAddress).cancelOrder(_orderIndex, true);

        _stf.totalRaised = remainingBalance;
        _stf.remainingAmountAfterClose = remainingBalance;
        _stf.status = StfStatus.CANCELLED;
        isManagingFund[_stf.manager] = false;

        emit NoFillVaultClosed(_stfxAddress);
    }

    /// @notice cancel the stf after a month and close the position as a market order
    /// @dev can only be called by the `admin` after the `maxDeadlineForPosition`, defaults to 30 days
    /// @param _stfxAddress address of the stf
    /// @param hasCloseOrder if true, the manager has created a close limit order
    /// @param _orderIndex the order index from the dex
    /// @param _triggerPrice price input depending on the latest price from the dex and whether its a limit or a market order
    /// @param _triggerAboveThreshold bool to check if the `triggerPrice` is above or below the `currentPrice`,
    function cancelStfAfterPositionDeadline(
        address _stfxAddress, 
        bool hasCloseOrder,
        uint256 _orderIndex,
        uint256 _triggerPrice,
        bool _triggerAboveThreshold
    ) external payable override whenNotPaused {
        StfInfo storage _stf = stfInfo[_stfxAddress];
        (uint256 _size,,,,,,) = getPosition(_stfxAddress);

        if(block.timestamp <= maxDeadlineForPosition) revert BelowMin(maxDeadlineForPosition, block.timestamp);
        if(msg.sender != admin) revert CantClose();
        if(_stf.status != StfStatus.CLOSED && _stf.status != StfStatus.OPENED) revert CantClose();
        if(_size < 1) revert NoOpenPositions();

        if(hasCloseOrder) {
            uint256 remainingBalance = IStfxGmx(_stfxAddress).cancelOrder(_orderIndex, false);
        }

        IStfxGmx(_stfxAddress).closePosition{value: msg.value}(
            false, _size, _triggerPrice, _triggerAboveThreshold
        );
        _stf.status = StfStatus.CLOSED;
        
        emit VaultClosed(_stfxAddress, _size, false, _triggerPrice, true);
    }

    /*//////////////////////////////////////////////////////////////
                            SETTER FUNCTIONS
    //////////////////////////////////////////////////////////////*/

    /// @notice set the max capacity of collateral which can be raised per stf
    /// @dev can only be called by the `owner`
    /// @param _capacity max capacity of the collateral which can be raised per stf
    function setCapacityPerStf(uint256 _capacity) external override onlyOwner whenNotPaused {
        if (_capacity < 1) revert ZeroAmount();
        capacityPerStf = _capacity;
        emit CapacityPerStfChanged(_capacity);
    }

    /// @notice set the min investment of collateral an investor can invest per stf
    /// @dev can only be called by the `owner`
    /// @param _amount min investment of collateral an investor can invest per stf
    function setMinInvestmentAmount(uint256 _amount) external override onlyOwner whenNotPaused {
        if (_amount < 1) revert ZeroAmount();
        minInvestmentAmount = _amount;
        emit MinInvestmentAmountChanged(_amount);
    }

    /// @notice set the max investment of collateral an investor can invest per stf
    /// @dev can only be called by the `owner`
    /// @param _amount max investment of collateral an investor can invest per stf
    function setMaxInvestmentAmount(uint256 _amount) external override onlyOwner whenNotPaused {
        if (_amount <= minInvestmentAmount) revert BelowMin(minInvestmentAmount, _amount);
        maxInvestmentAmount = _amount;
        emit MaxInvestmentAmountChanged(_amount);
    }

    /// @notice set the max leverage a manager can use when creating an stf
    /// @dev can only be called by the `owner`
    /// @param _maxLeverage max leverage a manager can use when creating an stf
    function setMaxLeverage(uint256 _maxLeverage) external override onlyOwner whenNotPaused {
        if (_maxLeverage <= 1e6) revert AboveMax(1e6, _maxLeverage);
        maxLeverage = _maxLeverage;
        emit MaxLeverageChanged(_maxLeverage);
    }

    function setMinLeverage(uint256 _minLeverage) external override onlyOwner whenNotPaused {
        if (_minLeverage < 1e6) revert BelowMin(1e16, _minLeverage);
        minLeverage = _minLeverage;
        emit MinLeverageChanged(_minLeverage);
    }

    /// @notice set the max fundraising period a manager can use when creating an stf
    /// @dev can only be called by the `owner`
    /// @param _maxFundraisingPeriod max fundraising period a manager can use when creating an stf
    function setMaxFundraisingPeriod(uint256 _maxFundraisingPeriod) external onlyOwner whenNotPaused {
        if (_maxFundraisingPeriod < 15 minutes) revert BelowMin(15 minutes, _maxFundraisingPeriod);
        maxFundraisingPeriod = _maxFundraisingPeriod;
        emit MaxFundraisingPeriodChanged(_maxFundraisingPeriod);
    }

    /// @notice set the max deadline a position can be open for an stf
    /// @dev can only be called by the `owner`
    /// @param _maxDeadlineForPosition max deadline a position can be open for an stf (default - 30 days)
    function setMaxDeadlineForPosition(uint256 _maxDeadlineForPosition) external onlyOwner whenNotPaused {
        if(_maxDeadlineForPosition < 1 days) revert BelowMin(1 days, _maxDeadlineForPosition);
        maxDeadlineForPosition = _maxDeadlineForPosition;
        emit MaxDeadlineForPositionChanged(_maxDeadlineForPosition);
    }

    /// @notice set the manager fee percent to calculate the manager fees on profits depending on the governance
    /// @dev can only be called by the `owner`
    /// @param newManagerFee the percent which is used to calculate the manager fees on profits
    function setManagerFee(uint256 newManagerFee) external override onlyOwner whenNotPaused {
        managerFee = newManagerFee;
        emit ManagerFeeChanged(newManagerFee);
    }

    /// @notice set the protocol fee percent to calculate the protocol fees on profits depending on the governance
    /// @dev can only be called by the `owner`
    /// @param newProtocolFee the percent which is used to calculate the protocol fees on profits
    function setProtocolFee(uint256 newProtocolFee) external override onlyOwner whenNotPaused {
        protocolFee = newProtocolFee;
        emit ProtocolFeeChanged(newProtocolFee);
    }

    /// @notice set the new owner of the StfxVault contract
    /// @dev can only be called by the current `owner`
    /// @param newOwner the new owner of the StfxVault contract
    function setOwner(address newOwner) external override onlyOwner {
        if (newOwner == address(0)) revert ZeroAddress();
        owner = newOwner;
        emit OwnerChanged(newOwner);
    }

    /// @notice set the new stfx implementation contract address for creating stfs
    /// @dev can only be called by the `owner`
    /// @param stfx the new stfx implementation contract address for creating stfs
    function setStfxImplementation(address stfx) external override onlyOwner {
        stfxImplementation = stfx;
        emit StfxImplementationChanged(stfx);
    }

    /// @notice set the new reader contract address
    /// @dev can only be called by the `owner`
    /// @param _reader the new reader contract address
    function setReader(address _reader) external override onlyOwner {
        reader = IReader(_reader);
        emit ReaderAddressChanged(_reader);
    }

    /// @notice set the `fundDeadline` for a particular stf to cancel the vault early if needed
    /// @dev can only be called by the `owner` or the `manager` of the stf
    /// @param _stfxAddress address of the stf
    /// @param newFundDeadline new fundDeadline
    function setFundDeadline(address _stfxAddress, uint256 newFundDeadline) external override {
        StfInfo storage _stf = stfInfo[_stfxAddress];
        if (msg.sender != _stf.manager && msg.sender != owner) revert NoAccess(_stf.manager, msg.sender);
        if (newFundDeadline > 72 hours) revert AboveMax(72 hours, newFundDeadline);
        _stf.fundDeadline = newFundDeadline;
        emit FundDeadlineChanged(_stfxAddress, newFundDeadline);
    }

    /// @notice set the usdc address
    /// @dev can only be called by the `owner`
    /// @param _usdc the usdc address
    function setUsdc(address _usdc) external onlyOwner {
        if (_usdc == address(0)) revert ZeroAddress();
        USDC = _usdc;
        emit UsdcAddressChanged(_usdc);
    }

    /// @notice set the weth address
    /// @dev can only be called by the `owner`
    /// @param _weth the weth address
    function setWeth(address _weth) external onlyOwner {
        if (_weth == address(0)) revert ZeroAddress();
        WETH = _weth;
        emit WethAddressChanged(_weth);
    }

    /// @notice set the admin address
    /// @dev can only be called by the `owner`
    /// @param _admin the admin address
    function setAdmin(address _admin) external onlyOwner {
        if (_admin == address(0)) revert ZeroAddress();
        admin = _admin;
        emit AdminChanged(_admin);
    }

    /// @notice set the treasury address
    /// @dev can only be called by the `owner`
    /// @param _treasury the treasury address
    function setTreasury(address _treasury) external onlyOwner {
        if (_treasury == address(0)) revert ZeroAddress();
        treasury = _treasury;
        emit TreasuryChanged(_treasury);
    }

    /// @notice set the referralCode from the dex depending on the governance
    /// @dev can only be called by the `owner`
    /// @param _referralCode the referralCode from the dex depending on the governance
    function setReferralCode(bytes32 _referralCode) external onlyOwner {
        referralCode = _referralCode;
        emit ReferralCodeChanged(_referralCode);
    }

    /// @notice Set the `status` of an stf in case of an emergency
    /// @dev is called only from the `Stfx` contract and reverts if called by another address
    /// @param _status new `status` of the stf
    function setStfStatus(StfStatus _status) external override {
        StfInfo storage _stf = stfInfo[msg.sender];
        if(_stf.stfxAddress != msg.sender) revert ZeroAddress();
        _stf.status = _status;
        emit StfStatusUpdate(msg.sender, _status);
    }

    /// @notice Set the `totalRaised` of an stf in case of an emergency
    /// @dev is called only from the `Stfx` contract and reverts if called by another address
    /// @param _totalRaised new `totalRaised` of the stf
    function setStfTotalRaised(uint256 _totalRaised) external override {
        StfInfo storage _stf = stfInfo[msg.sender];
        if(_stf.stfxAddress != msg.sender) revert ZeroAddress();
        _stf.totalRaised = _totalRaised;
        emit StfTotalRaisedUpdate(msg.sender, _totalRaised);
    }

    /// @notice Set the `remainingAmountAfterClose` of an stf in case of an emergency
    /// @dev is called only from the `Stfx` contract and reverts if called by another address
    /// @param _remainingBalance new `remainingAmountAfterClose` of the stf
    function setStfRemainingBalance(uint256 _remainingBalance) external override {
        StfInfo storage _stf = stfInfo[msg.sender];
        if(_stf.stfxAddress != msg.sender) revert ZeroAddress();
        _stf.remainingAmountAfterClose = _remainingBalance;
        emit StfRemainingBalanceUpdate(msg.sender, _remainingBalance);
    }

    /// @notice Set the `isManagingFund` state to true or false depending on the emergency
    /// @dev Can only be called by the owner
    /// @param _manager address of the manager
    /// @param _isManaging true if already managing an stf and false if not managing an stf
    function setIsManagingFund(address _manager, bool _isManaging) external override onlyOwner {
        isManagingFund[_manager] = _isManaging;
        emit ManagingFundUpdate(_manager, _isManaging);
    }

    /*//////////////////////////////////////////////////////////////
                            WITHDRAW
    //////////////////////////////////////////////////////////////*/

    /// @notice Transfer `Eth` from this contract to the `receiver` in case of emergency
    /// @dev Can be called only by the `owner`
    /// @param receiver address of the `receiver`
    /// @param amount amount to be withdrawn
    function withdrawEth(address receiver, uint256 amount) external override onlyOwner {
        if (receiver == address(0)) revert ZeroAddress();
        uint256 balance = address(this).balance;
        if(amount > balance) revert AboveMax(balance, amount);
        payable(receiver).transfer(amount);
        emit WithdrawEth(receiver, amount);
    }

    /// @notice Transfer `ERC20` token from this contract to the `receiver` in case of emergency
    /// @dev Can be called only by the `owner`
    /// @param token address of the `ERC20` token
    /// @param receiver address of the `receiver`
    /// @param amount amount to be withdrawn
    function withdrawToken(address token, address receiver, uint256 amount) external override onlyOwner {
        if (receiver == address(0)) revert ZeroAddress();
        uint256 balance = IERC20(token).balanceOf(address(this));
        if(amount > balance) revert AboveMax(balance, amount);
        IERC20(token).transfer(receiver, amount);
        emit WithdrawToken(token, receiver, amount);
    }

    /// @notice Transfer `ERC20` token from this contract to the `receiver` in case of emergency
    /// @dev Can be called only by the `owner`
    /// @param _stfxAddress address of the stf
    /// @param receiver address of the `receiver`
    /// @param isEth bool true if withdrawing `Eth` from `Stfx` contract, else withdrawing ERC20 `token`
    /// @param token address of the `ERC20` token
    function withdrawFromStf(
        address _stfxAddress, 
        address receiver, 
        bool isEth, 
        address token,
        uint256 amount
    )
        external
        override
        onlyOwner
    {
        if (receiver == address(0)) revert ZeroAddress();
        uint256 balance;
        if (isEth) {
            balance = address(_stfxAddress).balance;
        } else {
            balance = IERC20(token).balanceOf(_stfxAddress);
        }
        if(amount > balance) revert AboveMax(balance, amount);
        IStfxGmx(_stfxAddress).withdraw(receiver, isEth, token, amount);
        emit WithdrawFromStf(_stfxAddress, receiver, isEth, token, amount);
    }

    /*//////////////////////////////////////////////////////////////
                          PAUSE/UNPAUSE
    //////////////////////////////////////////////////////////////*/

    /// @notice Pause contract
    /// @dev can only be called by the `owner` when the contract is not paused
    function pause() public onlyAdmin whenNotPaused {
        _pause();
    }

    /// @notice Unpause contract
    /// @dev can only be called by the `owner` when the contract is paused
    function unpause() public onlyAdmin whenPaused {
        _unpause();
    }
}

File 4 of 34 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

File 5 of 34 : IStfx.sol
//SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

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

interface IStfx is IStfxStorage {
    event Initialized(address indexed manager, address indexed stfxAddress, address indexed vault);

    function initialize(Stf calldata _stf, address _manager, address _usdc, address _weth, address _reader) external;

    function remainingBalance() external view returns (uint256);
}

File 6 of 34 : IStfxPerp.sol
//SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import {IStfxStorage} from "src/interfaces/IStfxStorage.sol";

interface IStfxPerp is IStfxStorage {
    event FundDeadlineChanged(uint256 newDeadline, address indexed stfxAddress);
    event ManagerAddressChanged(address indexed newManager, address indexed stfxAddress);
    event ReferralCodeChanged(bytes32 newReferralCode, address indexed stfxAddress);
    event ClaimedUSDC(address indexed investor, uint256 claimAmount, uint256 timeOfClaim, address indexed stfxAddress);
    event VaultLiquidated(uint256 timeOfLiquidation, address indexed stfxAddress);
    event NoFillVaultClosed(uint256 timeOfClose, address indexed stfxAddress);
    event TradeDeadlineChanged(uint256 newTradeDeadline, address indexed stfxAddress);

    function openPosition() external returns (bool);

    function closePosition() external returns (bool);
}

File 7 of 34 : IGmxVault.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import "./IGmxVaultUtils.sol";

interface IGmxVault {
    function isInitialized() external view returns (bool);

    function isSwapEnabled() external view returns (bool);

    function isLeverageEnabled() external view returns (bool);

    function setVaultUtils(IGmxVaultUtils _vaultUtils) external;

    function setError(uint256 _errorCode, string calldata _error) external;

    function router() external view returns (address);

    function usdg() external view returns (address);

    function gov() external view returns (address);

    function whitelistedTokenCount() external view returns (uint256);

    function maxLeverage() external view returns (uint256);

    function minProfitTime() external view returns (uint256);

    function hasDynamicFees() external view returns (bool);

    function fundingInterval() external view returns (uint256);

    function totalTokenWeights() external view returns (uint256);

    function getTargetUsdgAmount(address _token) external view returns (uint256);

    function inManagerMode() external view returns (bool);

    function inPrivateLiquidationMode() external view returns (bool);

    function maxGasPrice() external view returns (uint256);

    function approvedRouters(address _account, address _router) external view returns (bool);

    function isLiquidator(address _account) external view returns (bool);

    function isManager(address _account) external view returns (bool);

    function minProfitBasisPoints(address _token) external view returns (uint256);

    function tokenBalances(address _token) external view returns (uint256);

    function lastFundingTimes(address _token) external view returns (uint256);

    function setMaxLeverage(uint256 _maxLeverage) external;

    function setInManagerMode(bool _inManagerMode) external;

    function setManager(address _manager, bool _isManager) external;

    function setIsSwapEnabled(bool _isSwapEnabled) external;

    function setIsLeverageEnabled(bool _isLeverageEnabled) external;

    function setMaxGasPrice(uint256 _maxGasPrice) external;

    function setUsdgAmount(address _token, uint256 _amount) external;

    function setBufferAmount(address _token, uint256 _amount) external;

    function setMaxGlobalShortSize(address _token, uint256 _amount) external;

    function setInPrivateLiquidationMode(bool _inPrivateLiquidationMode) external;

    function setLiquidator(address _liquidator, bool _isActive) external;

    function setFundingRate(uint256 _fundingInterval, uint256 _fundingRateFactor, uint256 _stableFundingRateFactor)
        external;

    function setFees(
        uint256 _taxBasisPoints,
        uint256 _stableTaxBasisPoints,
        uint256 _mintBurnFeeBasisPoints,
        uint256 _swapFeeBasisPoints,
        uint256 _stableSwapFeeBasisPoints,
        uint256 _marginFeeBasisPoints,
        uint256 _liquidationFeeUsd,
        uint256 _minProfitTime,
        bool _hasDynamicFees
    ) external;

    function setTokenConfig(
        address _token,
        uint256 _tokenDecimals,
        uint256 _redemptionBps,
        uint256 _minProfitBps,
        uint256 _maxUsdgAmount,
        bool _isStable,
        bool _isShortable
    ) external;

    function setPriceFeed(address _priceFeed) external;

    function withdrawFees(address _token, address _receiver) external returns (uint256);

    function directPoolDeposit(address _token) external;

    function buyUSDG(address _token, address _receiver) external returns (uint256);

    function sellUSDG(address _token, address _receiver) external returns (uint256);

    function swap(address _tokenIn, address _tokenOut, address _receiver) external returns (uint256);

    function increasePosition(
        address _account,
        address _collateralToken,
        address _indexToken,
        uint256 _sizeDelta,
        bool _isLong
    ) external;

    function decreasePosition(
        address _account,
        address _collateralToken,
        address _indexToken,
        uint256 _collateralDelta,
        uint256 _sizeDelta,
        bool _isLong,
        address _receiver
    ) external returns (uint256);

    function liquidatePosition(
        address _account,
        address _collateralToken,
        address _indexToken,
        bool _isLong,
        address _feeReceiver
    ) external;

    function tokenToUsdMin(address _token, uint256 _tokenAmount) external view returns (uint256);

    function priceFeed() external view returns (address);

    function fundingRateFactor() external view returns (uint256);

    function stableFundingRateFactor() external view returns (uint256);

    function cumulativeFundingRates(address _token) external view returns (uint256);

    function getNextFundingRate(address _token) external view returns (uint256);

    function getFeeBasisPoints(
        address _token,
        uint256 _usdgDelta,
        uint256 _feeBasisPoints,
        uint256 _taxBasisPoints,
        bool _increment
    ) external view returns (uint256);

    function liquidationFeeUsd() external view returns (uint256);

    function taxBasisPoints() external view returns (uint256);

    function stableTaxBasisPoints() external view returns (uint256);

    function mintBurnFeeBasisPoints() external view returns (uint256);

    function swapFeeBasisPoints() external view returns (uint256);

    function stableSwapFeeBasisPoints() external view returns (uint256);

    function marginFeeBasisPoints() external view returns (uint256);

    function allWhitelistedTokensLength() external view returns (uint256);

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

    function whitelistedTokens(address _token) external view returns (bool);

    function stableTokens(address _token) external view returns (bool);

    function shortableTokens(address _token) external view returns (bool);

    function feeReserves(address _token) external view returns (uint256);

    function globalShortSizes(address _token) external view returns (uint256);

    function globalShortAveragePrices(address _token) external view returns (uint256);

    function maxGlobalShortSizes(address _token) external view returns (uint256);

    function tokenDecimals(address _token) external view returns (uint256);

    function tokenWeights(address _token) external view returns (uint256);

    function guaranteedUsd(address _token) external view returns (uint256);

    function poolAmounts(address _token) external view returns (uint256);

    function bufferAmounts(address _token) external view returns (uint256);

    function reservedAmounts(address _token) external view returns (uint256);

    function usdgAmounts(address _token) external view returns (uint256);

    function maxUsdgAmounts(address _token) external view returns (uint256);

    function getRedemptionAmount(address _token, uint256 _usdgAmount) external view returns (uint256);

    function getMaxPrice(address _token) external view returns (uint256);

    function getMinPrice(address _token) external view returns (uint256);

    function getDelta(
        address _indexToken,
        uint256 _size,
        uint256 _averagePrice,
        bool _isLong,
        uint256 _lastIncreasedTime
    ) external view returns (bool, uint256);

    function getPosition(address _account, address _collateralToken, address _indexToken, bool _isLong)
        external
        view
        returns (uint256, uint256, uint256, uint256, uint256, uint256, bool, uint256);

    function getPositionDelta(address _account, address _collateralToken, address _indexToken, bool _isLong)
        external
        view
        returns (bool, uint256);
}

File 8 of 34 : IStfxVault.sol
//SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

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

interface IStfxVault is IStfxStorage {
    event InitializedVault(
        address _reader,
        address _stfxImplementation,
        uint256 _capacityPerStf,
        uint256 _minInvestmentAmount,
        uint256 _maxInvestmentAmount,
        uint256 _maxLeverage,
        address _usdc,
        address _weth,
        address _admin,
        address _treasury
    );
    event NewFundCreated(
        address indexed baseToken,
        uint256 fundraisingPeriod,
        uint256 entryPrice,
        uint256 targetPrice,
        uint256 liquidationPrice,
        uint256 leverage,
        bool tradeDirection,
        address indexed stfxAddress,
        address indexed manager
    );
    event DepositIntoFund(address indexed _stfxAddress, address indexed investor, uint256 amount);
    event FundraisingClosed(address indexed _stfxAddress);
    event FundraisingCloseAndVaultOpened(address indexed _stfxAddress, bool _isLimit, uint256 triggerPrice);
    event VaultOpened(address indexed _stfAddress, bool isLimit, uint256 triggerPrice);
    event VaultClosed(
        address indexed _stfAddress, uint256 size, bool isLimit, uint256 triggerPrice, bool closedCompletely
    );
    event OrderUpdated(
        address indexed _stfxAddress, uint256 _size, uint256 _triggerPrice, bool _isOpen, bool _triggerAboveThreshold
    );
    event OrderCancelled(address indexed _stfxAddress, uint256 _orderIndex, bool _isOpen, uint256 _totalRaised);
    event CreatedPositionAgain(address indexed _stfxAddress, bool _isOpen, uint256 _triggerPrice);
    event FeesTransferred(
        address indexed _stfxAddress, uint256 _remainingBalance, uint256 _managerFee, uint256 _protocolFee
    );
    event Claimed(address indexed investor, address indexed stfxAddress, uint256 amount);
    event VaultLiquidated(address indexed stfxAddress);
    event NoFillVaultClosed(address indexed stfxAddress);
    event CapacityPerStfChanged(uint256 capacity);
    event MaxInvestmentAmountChanged(uint256 maxAmount);
    event MinInvestmentAmountChanged(uint256 maxAmount);
    event MaxLeverageChanged(uint256 maxLeverage);
    event MinLeverageChanged(uint256 minLeverage);
    event MaxFundraisingPeriodChanged(uint256 maxFundraisingPeriod);
    event ManagerFeeChanged(uint256 managerFee);
    event ProtocolFeeChanged(uint256 protocolFee);
    event OwnerChanged(address indexed newOwner);
    event StfxImplementationChanged(address indexed stfx);
    event ReaderAddressChanged(address indexed reader);
    event FundDeadlineChanged(address indexed stfxAddress, uint256 fundDeadline);
    event MaxDeadlineForPositionChanged(uint256 maxDeadlineForPosition);
    event UsdcAddressChanged(address indexed usdc);
    event WethAddressChanged(address indexed weth);
    event AdminChanged(address indexed admin);
    event TreasuryChanged(address indexed treasury);
    event ReferralCodeChanged(bytes32 referralCode);
    event WithdrawEth(address indexed receiver, uint256 amount);
    event WithdrawToken(address indexed token, address indexed receiver, uint256 amount);
    event WithdrawFromStf(
        address indexed stfxAddress, address indexed receiver, bool isEth, address indexed token, uint256 amount
    );
    event StfStatusUpdate(address indexed stfxAddress, StfStatus status);
    event StfTotalRaisedUpdate(address indexed stfxAddress, uint256 totalRaised);
    event StfRemainingBalanceUpdate(address indexed stfxAddress, uint256 remainingBalance);
    event ManagingFundUpdate(address indexed manager, bool isManaging);

    function getUserAmount(address _stfxAddress, address _investor) external view returns (uint256);

    function getClaimAmount(address _stfxAddress, address _investor) external view returns (uint256);

    function getClaimed(address _stfxAddress, address _investor) external view returns (bool);

    function getPosition(address _stfxAddress)
        external
        view
        returns (uint256, uint256, uint256, uint256, uint256, uint256, bool);

    function shouldDistribute(address _stfxAddress) external view returns (bool);

    function isDistributed(address _stfxAddress) external view returns (bool);

    function isClosed(address _stfxAddress) external view returns (bool);

    function isOpened(address _stfxAddress) external view returns (bool);

    function createNewStf(Stf calldata _fund) external returns (address);

    function depositIntoFund(address _stfxAddress, uint256 amount) external;

    function closeFundraising(address _stfxAddress) external;

    function closeFundraisingAndOpenPosition(address _stfxAddress, bool _isLimit, uint256 _triggerPrice)
        external
        payable;

    function openPosition(address _stfxAddress, bool _isLimit, uint256 _triggerPrice) external payable;

    function closePosition(
        address _stfxAddress,
        bool _isLimit,
        uint256 _size,
        uint256 _triggerPrice,
        bool _triggerAboveThreshold
    ) external payable;

    function distributeProfits(address _stfxAddress) external;

    function cancelOrder(address _stfxAddress, uint256 _orderIndex, bool _isOpen) external;

    function createPositionAgain(
        address _stfxAddress,
        bool _isLimit,
        bool _isOpen,
        uint256 _size,
        uint256 _triggerPrice,
        bool _triggerAboveThreshold
    ) external payable;

    function claimableAmount(address _stfxAddress, address _investor) external view returns (uint256);

    function claim(address _stfxAddress) external;

    function closeLiquidatedVault(address _stfxAddress) external;

    function cancelVault(address _stfxAddress) external;

    function cancelStfByManager(address _stfxAddress) external;

    function cancelStfAfterOpening(address _stfxAddress, uint256 _orderIndex) external;

    function cancelStfAfterPositionDeadline(
        address _stfxAddress, 
        bool hasCloseOrder,
        uint256 _orderIndex,
        uint256 _triggerPrice,
        bool _triggerAboveThreshold
    ) external payable;

    function setCapacityPerStf(uint256 _capacity) external;

    function setMinInvestmentAmount(uint256 _amount) external;

    function setMaxInvestmentAmount(uint256 _amount) external;

    function setMaxLeverage(uint256 _maxLeverage) external;

    function setMinLeverage(uint256 _minLeverage) external;

    // function setNewManager(address _stfxAddress, address _manager) external;

    function setManagerFee(uint256 _managerFee) external;

    function setProtocolFee(uint256 _protocolFee) external;

    function setOwner(address _owner) external;

    function setStfxImplementation(address _stfx) external;

    function setReader(address _reader) external;

    function setFundDeadline(address _stfx, uint256 _fundDeadline) external;

    function setStfStatus(StfStatus) external;

    function setStfTotalRaised(uint256 totalRaised) external;

    function setStfRemainingBalance(uint256 remainingBalance) external;

    function setIsManagingFund(address _manager, bool _isManaging) external;

    function withdrawEth(address receiver, uint256 amount) external;

    function withdrawToken(address token, address receiver, uint256 amount) external;

    function withdrawFromStf(address _stfxAddress, address receiver, bool isEth, address token, uint256 amount) external;
}

File 9 of 34 : Clones.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (proxy/Clones.sol)

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) {
        /// @solidity memory-safe-assembly
        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) {
        /// @solidity memory-safe-assembly
        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) {
        /// @solidity memory-safe-assembly
        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 10 of 34 : Pausable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)

pragma solidity ^0.8.0;

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

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract Pausable is Context {
    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    bool private _paused;

    /**
     * @dev Initializes the contract in unpaused state.
     */
    constructor() {
        _paused = false;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        _requireNotPaused();
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        _requirePaused();
        _;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        return _paused;
    }

    /**
     * @dev Throws if the contract is paused.
     */
    function _requireNotPaused() internal view virtual {
        require(!paused(), "Pausable: paused");
    }

    /**
     * @dev Throws if the contract is not paused.
     */
    function _requirePaused() internal view virtual {
        require(paused(), "Pausable: not paused");
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }
}

File 11 of 34 : IReader.sol
//SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import {IReaderStorage} from "src/interfaces/IReaderStorage.sol";

interface IReader is IReaderStorage {
    function getDex() external view returns (address[] memory);
    function getBaseTokenEligible(address _baseToken) external view returns (bool);
    function getPrice(address _baseToken) external view returns (uint256, uint256);
    function checkPrices(uint256 _entry, uint256 _target, address _baseToken, bool _tradeDirection)
        external
        view
        returns (bool);
}

File 12 of 34 : IGmxVaultUtils.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

interface IGmxVaultUtils {
    function updateCumulativeFundingRate(address _collateralToken, address _indexToken) external returns (bool);
    function validateIncreasePosition(
        address _account,
        address _collateralToken,
        address _indexToken,
        uint256 _sizeDelta,
        bool _isLong
    ) external view;
    function validateDecreasePosition(
        address _account,
        address _collateralToken,
        address _indexToken,
        uint256 _collateralDelta,
        uint256 _sizeDelta,
        bool _isLong,
        address _receiver
    ) external view;
    function validateLiquidation(
        address _account,
        address _collateralToken,
        address _indexToken,
        bool _isLong,
        bool _raise
    ) external view returns (uint256, uint256);
    function getEntryFundingRate(address _collateralToken, address _indexToken, bool _isLong)
        external
        view
        returns (uint256);
    function getPositionFee(
        address _account,
        address _collateralToken,
        address _indexToken,
        bool _isLong,
        uint256 _sizeDelta
    ) external view returns (uint256);
    function getFundingFee(
        address _account,
        address _collateralToken,
        address _indexToken,
        bool _isLong,
        uint256 _size,
        uint256 _entryFundingRate
    ) external view returns (uint256);
    function getBuyUsdgFeeBasisPoints(address _token, uint256 _usdgAmount) external view returns (uint256);
    function getSellUsdgFeeBasisPoints(address _token, uint256 _usdgAmount) external view returns (uint256);
    function getSwapFeeBasisPoints(address _tokenIn, address _tokenOut, uint256 _usdgAmount)
        external
        view
        returns (uint256);
    function getFeeBasisPoints(
        address _token,
        uint256 _usdgDelta,
        uint256 _feeBasisPoints,
        uint256 _taxBasisPoints,
        bool _increment
    ) external view returns (uint256);
}

File 13 of 34 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

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 14 of 34 : IReaderStorage.sol
//SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

interface IReaderStorage {
    struct Perp {
        address vault;
        address marketRegistry;
        address clearingHouse;
    }

    struct Gmx {
        address vault;
        address router;
        address positionRouter;
        address orderBook;
        address reader;
    }
}

File 15 of 34 : Stfx.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.15;

import {StfxVault} from "src/StfxVault.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IStfx} from "src/interfaces/IStfx.sol";
import {IStfxPerp} from "src/perp/interfaces/IStfxPerp.sol";
import {IMarketRegistry} from "src/interfaces/external/perp/IMarketRegistry.sol";
import {IBaseToken} from "src/interfaces/external/perp/IBaseToken.sol";
import {IVault} from "src/interfaces/external/perp/IVault.sol";
import {IClearingHouse} from "src/interfaces/external/perp/IClearingHouse.sol";
import {IReader} from "src/interfaces/IReader.sol";

contract Stfx is IStfx, IStfxPerp {
    address private USDC;
    address private WETH;

    bool private calledInitialize;
    bool private calledOpen;

    address public manager;

    Stf public stf;
    StfxVault public vault;
    IReader public reader;

    bytes32 public referralCode;

    uint256 public remainingBalance;
    uint256 public managerFee;
    uint256 public protocolFee;

    /// @notice modifier to make sure the initalize() is called only once
    modifier initOnce() {
        require(!calledInitialize, "can only initialize once");
        calledInitialize = true;
        _;
    }

    modifier onlyVault() {
        require(msg.sender == address(vault), "onlyVault");
        _;
    }

    modifier openOnce() {
        require(!calledOpen, "can only open once");
        calledOpen = true;
        _;
    }

    function initialize(Stf calldata _stf, address _manager, address _usdc, address _weth, address _reader)
        external
        override
        initOnce
    {
        stf = _stf;
        manager = _manager;
        vault = StfxVault(msg.sender);
        USDC = _usdc;
        WETH = _weth;
        reader = IReader(_reader);
        emit Initialized(_manager, address(this), msg.sender);
    }

    function openPosition() external override onlyVault openOnce returns (bool) {
        Stf memory _stf = stf;
        address[] memory _dex = reader.getDex();

        (,, uint256 _totalRaised,,,,) = vault.stfInfo(address(this));

        IERC20(USDC).approve(_dex[0], _totalRaised);
        IVault(_dex[0]).deposit(USDC, _totalRaised);

        if (_stf.tradeDirection) {
            // long
            IClearingHouse(_dex[2]).openPosition(
                IClearingHouse.OpenPositionParams({
                    baseToken: _stf.baseToken,
                    isBaseToQuote: !_stf.tradeDirection,
                    isExactInput: true,
                    amount: _totalRaised * _stf.leverage * 1e12,
                    oppositeAmountBound: 0,
                    sqrtPriceLimitX96: 0,
                    deadline: block.timestamp + 900,
                    referralCode: referralCode
                })
            );
        } else {
            // short
            IClearingHouse(_dex[2]).openPosition(
                IClearingHouse.OpenPositionParams({
                    baseToken: _stf.baseToken,
                    isBaseToQuote: !_stf.tradeDirection,
                    isExactInput: false,
                    amount: _totalRaised * _stf.leverage * 1e12,
                    oppositeAmountBound: 0,
                    sqrtPriceLimitX96: 0,
                    deadline: block.timestamp + 900,
                    referralCode: referralCode
                })
            );
        }
        return true;
    }

    function closePosition() external override onlyVault returns (bool) {
        Stf memory _stf = stf;
        address[] memory _dex = reader.getDex();

        IClearingHouse(_dex[2]).closePosition(
            IClearingHouse.ClosePositionParams({
                baseToken: _stf.baseToken,
                oppositeAmountBound: 0,
                sqrtPriceLimitX96: 0,
                deadline: block.timestamp + 900,
                referralCode: referralCode
            })
        );

        uint256 collateralBalance = IVault(_dex[0]).getFreeCollateral(address(this));
        IVault(_dex[0]).withdraw(USDC, collateralBalance);
        uint256 usdcBalance = IERC20(USDC).balanceOf(address(this));

        uint256 profits;

        (,, uint256 _totalRaised,,,,) = vault.stfInfo(address(this));

        if (usdcBalance > _totalRaised) {
            profits = usdcBalance - _totalRaised;
            managerFee = (profits * vault.managerFee()) / 100e18;
            protocolFee = (profits * vault.protocolFee()) / 100e18;

            IERC20(USDC).transfer(manager, managerFee);
            IERC20(USDC).transfer(vault.owner(), protocolFee);

            remainingBalance = IERC20(USDC).balanceOf(address(this));
        } else {
            remainingBalance = usdcBalance;
        }

        IERC20(USDC).transfer(address(vault), remainingBalance);
        return true;
    }
}

File 16 of 34 : IMarketRegistry.sol
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;

interface IMarketRegistry {
    function hasPool(address baseToken) external view returns (bool);
}

File 17 of 34 : IBaseToken.sol
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;

interface IBaseToken {
    function getIndexPrice(uint256 interval) external view returns (uint256);
}

File 18 of 34 : IVault.sol
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;

interface IVault {
    event Deposited(address indexed collateralToken, address indexed trader, uint256 amount);

    event Withdrawn(address indexed collateralToken, address indexed trader, uint256 amount);

    /// @param token the address of the token to deposit;
    ///        once multi-collateral is implemented, the token is not limited to settlementToken
    /// @param amountX10_D the amount of the token to deposit in decimals D (D = _decimals)
    // solhint-disable-next-line
    function deposit(address token, uint256 amountX10_D) external;

    /// @param token the address of the token sender is going to withdraw
    ///        once multi-collateral is implemented, the token is not limited to settlementToken
    /// @param amountX10_D the amount of the token to withdraw in decimals D (D = _decimals)
    // solhint-disable-next-line
    function withdraw(address token, uint256 amountX10_D) external;

    function getBalanceByToken(address trader, address token) external view returns (int256);

    /// @param trader The address of the trader to query
    /// @return freeCollateral Max(0, amount of collateral available for withdraw or opening new positions or orders)
    function getFreeCollateral(address trader) external view returns (uint256);

    /// @dev there are three configurations for different insolvency risk tolerances: conservative, moderate, aggressive
    ///      we will start with the conservative one and gradually move to aggressive to increase capital efficiency
    /// @param trader the address of the trader
    /// @param ratio the margin requirement ratio, imRatio or mmRatio
    /// @return freeCollateralByRatio freeCollateral, by using the input margin requirement ratio; can be negative
    function getFreeCollateralByRatio(address trader, uint24 ratio) external view returns (int256);

    function getSettlementToken() external view returns (address);

    /// @dev cached the settlement token's decimal for gas optimization
    function decimals() external view returns (uint8);

    function getTotalDebt() external view returns (uint256);

    function getClearingHouseConfig() external view returns (address);

    function getAccountBalance() external view returns (address);

    function getInsuranceFund() external view returns (address);

    function getExchange() external view returns (address);

    function getClearingHouse() external view returns (address);

    function getSettlementTokenValue(address trader) external view returns (int256);

    /// @notice Get account value (denominated in settlement token) of the specified trader
    /// @param trader The address of the trader
    /// @return accountValue account value (in settlement token's decimals)
    function getAccountValue(address trader) external view returns (int256);
}

File 19 of 34 : IClearingHouse.sol
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;

interface IClearingHouse {
    struct OpenPositionParams {
        address baseToken;
        bool isBaseToQuote;
        bool isExactInput;
        uint256 amount;
        // B2Q + exact input, want more output quote as possible, so we set a lower bound of output quote
        // B2Q + exact output, want less input base as possible, so we set a upper bound of input base
        // Q2B + exact input, want more output base as possible, so we set a lower bound of output base
        // Q2B + exact output, want less input quote as possible, so we set a upper bound of input quote
        // when it's 0 in exactInput, means ignore slippage protection
        // when it's maxUint in exactOutput = ignore
        // when it's over or under the bound, it will be reverted
        uint256 oppositeAmountBound;
        uint256 deadline;
        // B2Q: the price cannot be less than this value after the swap
        // Q2B: The price cannot be greater than this value after the swap
        // it will fill the trade until it reach the price limit instead of reverted
        uint160 sqrtPriceLimitX96;
        bytes32 referralCode;
    }

    struct ClosePositionParams {
        address baseToken;
        uint160 sqrtPriceLimitX96;
        uint256 oppositeAmountBound;
        uint256 deadline;
        bytes32 referralCode;
    }

    function openPosition(OpenPositionParams memory params) external returns (uint256 deltaBase, uint256 deltaQuote);

    function closePosition(ClosePositionParams calldata params)
        external
        returns (uint256 deltaBase, uint256 deltaQuote);

    function getAccountValue(address trader) external view returns (int256);

    function getPositionSize(address trader, address baseToken) external view returns (int256);

    function getPositionValue(address trader, address baseToken) external view returns (int256);

    function getOpenNotional(address trader, address baseToken) external view returns (int256);

    function getOwedRealizedPnl(address trader) external view returns (int256);

    function getTotalInitialMarginRequirement(address trader) external view returns (uint256);

    function getNetQuoteBalance(address trader) external view returns (int256);

    function getTotalUnrealizedPnl(address trader) external view returns (int256);
}

File 20 of 34 : Reader.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.15;

import {IReader} from "src/interfaces/IReader.sol";
import {IMarketRegistry} from "src/interfaces/external/perp/IMarketRegistry.sol";
import {IBaseToken} from "src/interfaces/external/perp/IBaseToken.sol";

contract Reader is IReader {
    Perp public dex;

    constructor(Perp memory _dex) {
        dex = _dex;
    }

    function getDex() external view override returns (address[] memory dexAddress) {
        dexAddress = new address[](3);
        dexAddress[0] = dex.vault;
        dexAddress[1] = dex.marketRegistry;
        dexAddress[2] = dex.clearingHouse;
    }

    function getBaseTokenEligible(address _baseToken) external view override returns (bool) {
        return IMarketRegistry(dex.marketRegistry).hasPool(_baseToken);
    }

    function getPrice(address _baseToken) public view override returns (uint256, uint256) {
        return (IBaseToken(_baseToken).getIndexPrice(0), 1e12);
    }

    function checkPrices(uint256 _entry, uint256 _target, address _baseToken, bool _tradeDirection)
        external
        view
        returns (bool)
    {
        (uint256 price, uint256 denominator) = getPrice(_baseToken);
        uint256 lower = price / (denominator * 10);
        uint256 upper = (price * 10) / denominator;

        if (_tradeDirection) {
            require(lower <= _entry, "entry should be more than lower");
            require(_entry < _target, "entry should be less than target");
            require(_target <= upper, "target should be less than upper");
        } else {
            require(lower <= _target, "target should be more than lower");
            require(_target < _entry, "target should be less than entry");
            require(_entry <= upper, "entry should be less than upper");
        }

        return true;
    }
}

File 21 of 34 : Reader.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.15;

import {IReader} from "src/interfaces/IReader.sol";
import {IGmxVault} from "src/interfaces/external/gmx/IGmxVault.sol";
import {IBaseToken} from "src/interfaces/external/perp/IBaseToken.sol";
import {IGmxVaultPriceFeed} from "src/interfaces/external/gmx/IGmxVaultPriceFeed.sol";

/// @title Reader
/// @author 7811, abhi3700
/// @notice Contract with view functions to get more info on the Stfs
/// @dev this contract is used by the StfxVault and the Stfx contract
contract Reader is IReader {
    // struct which contains all the necessary contract addresses of GMX
    // check `IReaderStorage.Gmx`
    Gmx public dex;
    // owner/deployer of this contract
    address public owner;

    /// @notice constructor
    /// @param _dex `Gmx` struct which contains the necessary contract addresses of GMX
    constructor(Gmx memory _dex) {
        dex = _dex;
        owner = msg.sender;
    }

    /// @notice get gmx's contract addresses
    /// @dev view function
    /// @return dexAddress - an array of gmx's contract addresses
    ///         dexAddress[0] = Gmx.Vault
    ///         dexAddress[1] = Gmx.Router
    ///         dexAddress[2] = Gmx.PositionRouter
    ///         dexAddress[3] = Gmx.OrderBook
    ///         dexAddress[4] = Gmx.Reader
    function getDex() external view override returns (address[] memory dexAddress) {
        dexAddress = new address[](5);
        dexAddress[0] = dex.vault;
        dexAddress[1] = dex.router;
        dexAddress[2] = dex.positionRouter;
        dexAddress[3] = dex.orderBook;
        dexAddress[4] = dex.reader;
    }

    /// @notice checks if an ERC20 token can be used to open a trade on GMX
    /// @dev view function
    /// @param _baseToken address of the ERC20 token which is used for the trade
    /// @return true if the `_baseToken` is eligible
    function getBaseTokenEligible(address _baseToken) external view override returns (bool) {
        return IGmxVault(dex.vault).shortableTokens(_baseToken);
    }

    /// @notice gets the current price of the `_baseToken` from GMX
    /// @dev view function, the price returned from gmx is in 1e30 units
    /// @param _baseToken address of the ERC20 token which is used for the trade
    /// @return price - the current price of the `_baseToken`
    /// @return denominator - the denominator which is used in `checkPrices()`
    function getPrice(address _baseToken) public view override returns (uint256, uint256) {
        address vaultPriceFeed = IGmxVault(dex.vault).priceFeed();
        return (IGmxVaultPriceFeed(vaultPriceFeed).getPrice(_baseToken, true, true, false), 1e24);
    }

    /// @notice Explain to an end user what this does
    /// @dev Explain to a developer any extra details
    /// @param _entry the entry price which has been given as input from the manager when creating an stf
    /// @param _target the target price which has been given as input from the manager when creating an stf
    /// @param _baseToken the baseToken which the manager wants to open a trade in
    /// @param _tradeDirection the direction of the trade which the manager wants to open, true = long, false = short
    /// @return true if the entry and the target price are under the lower and the upper limit
    function checkPrices(uint256 _entry, uint256 _target, address _baseToken, bool _tradeDirection)
        external
        view
        returns (bool)
    {
        (uint256 price, uint256 denominator) = getPrice(_baseToken);
        uint256 lower = price / (denominator * 10);
        uint256 upper = (price * 10) / denominator;

        if (_tradeDirection) {
            require(lower <= _entry, "entry should be more than lower");
            require(_entry < _target, "entry should be less than target");
            require(_target <= upper, "target should be less than upper");
        } else {
            require(lower <= _target, "target should be more than lower");
            require(_target < _entry, "target should be less than entry");
            require(_entry <= upper, "entry should be less than upper");
        }

        return true;
    }

    /// @notice function to set/update the necessary contract addresses of gmx
    /// @dev can only be called by the owner
    /// @param _dex `Gmx` struct which contains the necessary contract addresses of GMX
    function setDex(Gmx calldata _dex) external {
        require(msg.sender == owner, "Not owner");
        dex = _dex;
    }
    
    /// @notice function to set the owner of the `Reader` contract
    /// @dev can only be called by the owner
    /// @param _owner new owner address
    function setOwner(address _owner) external {
        require(msg.sender == owner, "Not owner");
        require(_owner != address(0), "Not zero address");
        owner = _owner;
    }
}

File 22 of 34 : IGmxVaultPriceFeed.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

interface IGmxVaultPriceFeed {
    function adjustmentBasisPoints(address _token) external view returns (uint256);

    function isAdjustmentAdditive(address _token) external view returns (bool);

    function setAdjustment(address _token, bool _isAdditive, uint256 _adjustmentBps) external;

    function setUseV2Pricing(bool _useV2Pricing) external;

    function setIsAmmEnabled(bool _isEnabled) external;

    function setIsSecondaryPriceEnabled(bool _isEnabled) external;

    function setSpreadBasisPoints(address _token, uint256 _spreadBasisPoints) external;

    function setSpreadThresholdBasisPoints(uint256 _spreadThresholdBasisPoints) external;

    function setFavorPrimaryPrice(bool _favorPrimaryPrice) external;

    function setPriceSampleSpace(uint256 _priceSampleSpace) external;

    function setMaxStrictPriceDeviation(uint256 _maxStrictPriceDeviation) external;

    function getPrice(address _token, bool _maximise, bool _includeAmmPrice, bool _useSwapPricing)
        external
        view
        returns (uint256);

    function getAmmPrice(address _token) external view returns (uint256);

    function getPrimaryPrice(address _token, bool _maximise) external view returns (uint256);

    function setTokenConfig(address _token, address _priceFeed, uint256 _priceDecimals, bool _isStrictStable)
        external;
}

File 23 of 34 : IGmxReader.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

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

interface IGmxReader {
    function getAmountOut(IGmxVault _vault, address _tokenIn, address _tokenOut, uint256 _amountIn)
        external
        view
        returns (uint256, uint256);
    function getMaxAmountIn(IGmxVault _vault, address _tokenIn, address _tokenOut) external view returns (uint256);
    function getPositions(
        address _vault,
        address _account,
        address[] memory _collateralTokens,
        address[] memory _indexTokens,
        bool[] memory _isLong
    ) external view returns (uint256[] memory);
}

File 24 of 34 : Stfx.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.15;

import "lib/forge-std/src/Test.sol";
import {StfxVault} from "src/StfxVault.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IStfx} from "src/interfaces/IStfx.sol";
import {IStfxGmx} from "src/gmx/interfaces/IStfxGmx.sol";
import {IReader} from "src/interfaces/IReader.sol";
import {IGmxVault} from "src/interfaces/external/gmx/IGmxVault.sol";
import {IGmxReader} from "src/interfaces/external/gmx/IGmxReader.sol";
import {IGmxRouter} from "src/interfaces/external/gmx/IGmxRouter.sol";
import {IGmxPositionRouter} from "src/interfaces/external/gmx/IGmxPositionRouter.sol";
import {IGmxOrderBook} from "src/interfaces/external/gmx/IGmxOrderBook.sol";

error Initialised();
error ZeroInput();
error ZeroBalance();
error NotEqual(uint256 desired, uint256 given);
error AboveMax(uint256 max, uint256 given);
error BelowMin(uint256 min, uint256 given);
error NoAccess(address desired, address given);

/// @title Stfx
/// @author 7811, abhi3700
/// @notice Contract which acts as the STF (Single Trade Fund)
/// @dev this contract is used as the `account` on the dex
contract Stfx is IStfx, IStfxGmx {
    // usdc address
    address private USDC;
    // weth address
    address private WETH;

    // bool to check if `initialize()` has already been called
    bool private calledInitialize;
    // address of the manager
    address public manager;

    // contains all the details of the Stf
    // check `IStfxStorage.Stf`
    Stf public stf;
    // StfxVault contract
    // check `StfxVault.sol`
    StfxVault public vault;
    // Stfx Reader contract - contains view functions
    // check `./Reader.sol`
    IReader public reader;

    bytes32 public referralCode;
    // remaining collateral which we receive from the dex after closing the trade
    uint256 public remainingBalance;

    /// @notice modifier to make sure the initalize() is called only once
    modifier initOnce() {
        if (calledInitialize) revert Initialised();
        calledInitialize = true;
        _;
    }

    /// @notice modifier for the function to only be called by the StfxVault contract
    modifier onlyVault() {
        if (msg.sender != address(vault)) revert NoAccess(address(vault), msg.sender);
        _;
    }

    /// @notice modifier for the function to only be called by the manager
    modifier onlyManager() {
        (, address _manager,,,,,) = vault.stfInfo(address(this));
        if (msg.sender != _manager) revert NoAccess(_manager, msg.sender);
        _;
    }

    function getStf() external view returns (Stf memory) {
        return stf;
    }

    /// @notice initialize the STF
    /// @dev can only be initialized once
    /// @param _stf the `Stf` struct from `IStfxStorage` which contains the info of the stf
    /// @param _manager address of the manager who created the Stf
    /// @param _usdc USDC contract address
    /// @param _weth WETH contract address
    /// @param _reader `Reader` contract address
    function initialize(Stf calldata _stf, address _manager, address _usdc, address _weth, address _reader)
        external
        override
        initOnce
    {
        stf = _stf;
        manager = _manager;
        vault = StfxVault(msg.sender);
        USDC = _usdc;
        WETH = _weth;
        reader = IReader(_reader);
        emit Initialized(_manager, address(this), msg.sender);
    }

    /// @notice Creates an open position or an open order on GMX depending on the input by the manager
    /// @dev can only be called by the StfxVault contract
    /// @dev is payable since GMX has a small fee in ETH, which can be obtained by `IGmxPositionRouter.minExecutionFee();`
    /// @param isLimit if true, then its a limit order, else a market order
    /// @param _triggerPrice price input depending on the latest price from the dex and whether its a limit or a market order
    /// @param _totalRaised total raised amount by the Stf which will be transferred from StfxVault contract
    function openPosition(bool isLimit, uint256 _triggerPrice, uint256 _totalRaised)
        external
        payable
        override
        onlyVault
    {
        if (_triggerPrice < 1) revert ZeroInput();
        address[] memory _dex = reader.getDex();

        /// GMX checks if `msg.value >= fee` for closing positions, so we need 1 more WEI to pass.
        uint256 _fee = IGmxPositionRouter(_dex[2]).minExecutionFee();
        if (msg.value < _fee) revert NotEqual(_fee, msg.value);

        address[] memory _path;
        if (!stf.tradeDirection) {
            _path = new address[](1);
            _path[0] = USDC;
        } else {
            _path = new address[](2);
            _path[0] = USDC;
            _path[1] = stf.baseToken;
        }

        IERC20(USDC).approve(_dex[1], _totalRaised);
        if (isLimit) {
            IGmxRouter(_dex[1]).approvePlugin(_dex[3]);
            IGmxOrderBook(_dex[3]).createIncreaseOrder{value: _fee}(
                _path,
                _totalRaised,
                stf.baseToken,
                0,
                stf.leverage * _totalRaised * 1e18,
                stf.tradeDirection ? stf.baseToken : USDC,
                stf.tradeDirection,
                _triggerPrice * 1e24,
                stf.tradeDirection ? false : true,
                _fee,
                false
            );
        } else {
            IGmxRouter(_dex[1]).approvePlugin(_dex[2]);
            IGmxPositionRouter(_dex[2]).createIncreasePosition{value: _fee}(
                _path,
                stf.baseToken,
                _totalRaised,
                0,
                stf.leverage * _totalRaised * 1e18,
                stf.tradeDirection,
                _triggerPrice * 1e24,
                _fee,
                vault.referralCode(),
                address(0)
            );
        }
    }

    /// @notice Creates a close position or a close order on GMX depending on the input by the manager
    /// @dev can only be called by the StfxVault contract
    /// @dev is payable since GMX has a small fee in ETH, which can be obtained by `IGmxPositionRouter.minExecutionFee();`
    /// @dev the msg.value should be > fee and not >= fee (which means it has to be fee + 1) for it to succeed, GMX is designed that way
    /// @param isLimit if true, then its a limit order, else a market order
    /// @param _size the position size which the manager wants to close
    /// @param _triggerPrice price input depending on the latest price from the dex and whether its a limit or a market order
    /// @param _triggerAboveThreshold bool to check if the `triggerPrice` is above or below the `currentPrice`, used for SL/TP
    /// @return closed - true if the function creates a close position or a close order successfully with the entire position size which is open
    ///         false if the position is only closed partially
    function closePosition(bool isLimit, uint256 _size, uint256 _triggerPrice, bool _triggerAboveThreshold)
        external
        payable
        override
        onlyVault
        returns (bool closed)
    {
        if (_size < 1) revert ZeroInput();
        if (_triggerPrice < 1) revert ZeroInput();

        address[] memory _dex = reader.getDex();

        /// GMX checks if `msg.value > fee` for closing positions, so we need 1 more WEI to pass.
        uint256 _fee = IGmxPositionRouter(_dex[2]).minExecutionFee() + 1;
        if (msg.value < _fee) revert BelowMin(_fee, msg.value);

        address[] memory _path;
        if (!stf.tradeDirection) {
            _path = new address[](1);
            _path[0] = USDC;
        } else {
            _path = new address[](2);
            _path[0] = stf.baseToken;
            _path[1] = USDC;
        }

        _triggerPrice *= 1e24;

        if (isLimit) {
            IGmxRouter(_dex[1]).approvePlugin(_dex[3]);
            IGmxOrderBook(_dex[3]).createDecreaseOrder{value: _fee}(
                stf.baseToken, _size, stf.tradeDirection ? stf.baseToken : USDC, 0, stf.tradeDirection, _triggerPrice, _triggerAboveThreshold
            );
        } else {
            IGmxRouter(_dex[1]).approvePlugin(_dex[2]);
            IGmxPositionRouter(_dex[2]).createDecreasePosition{value: _fee}(
                _path, 
                stf.baseToken, 
                0, 
                _size, 
                stf.tradeDirection, 
                address(this), 
                _triggerPrice, 
                0, 
                _fee, 
                false, 
                address(0)
            );
        }

        return true;
    }

    /// @notice cancels an order which the manager had already created
    /// @dev can only be called by the StfxVault contract
    /// @dev transfers the remaining amount back to the StfxVault contract
    /// @dev in case of cancelling long open orders, it swaps back to the collateral which is used
    /// @dev it also transfers back the `fee` to the `manager` which was paid during opening or closing the order in ETH
    /// @param _orderIndex the index of the order which has to be cancelled, can be obtained from GMX
    /// @param _isOpen if true, the manager can cancel an open order, else, the manager can cancel a close order
    /// @return remaining amount of the collateral which we get back from GMX
    function cancelOrder(uint256 _orderIndex, bool _isOpen) external onlyVault returns (uint256 remaining) {
        address[] memory _dex = reader.getDex();
        if (_isOpen) {
            IGmxOrderBook(_dex[3]).cancelIncreaseOrder(_orderIndex);
            if (stf.tradeDirection) {
                if (stf.baseToken == WETH) {
                    uint256 _fee = IGmxPositionRouter(_dex[2]).minExecutionFee();
                    swapEthToTokens((address(this).balance - _fee));
                } else {
                    uint256 baseTokenBalance = IERC20(stf.baseToken).balanceOf(address(this));
                    swapTokens(stf.baseToken, baseTokenBalance);
                }
            }
        } else {
            IGmxOrderBook(_dex[3]).cancelDecreaseOrder(_orderIndex);
        }

        uint256 balance = address(this).balance;
        remaining = IERC20(USDC).balanceOf(address(this));

        if (balance > 0) payable(manager).transfer(balance);

        IERC20(USDC).transfer(address(vault), remaining);
    }

    /// @notice distributes the fees on profits to manager and protocol
    /// @notice and transfers back the remaining collateral to the StfxVault contract for the investors to claim back
    /// @dev gets the fee percent for manager and protocol from the StfxVault contract
    /// @dev if the contract receives baseToken from GMX when closing the trade, then it is swapped back to the collateral token
    /// @return remaining - the remaining collateral balance after profit or loss which is transferred to the StfxVault contract
    /// @return managerFee - the fee which is transferred to the manager in case of a profit
    /// @return protocolFee - the fee which is transferred to the protocol in case of a profit
    function distributeProfits()
        public
        override
        onlyVault
        returns (uint256 remaining, uint256 managerFee, uint256 protocolFee)
    {
        Stf memory _stf = stf;
        uint256 _totalRaised = vault.actualTotalRaised(address(this));

        uint256 baseTokenBalance = IERC20(_stf.baseToken).balanceOf(address(this));
        address[] memory path = new address[](2);
        path[1] = USDC;

        if (address(this).balance > 0) swapEthToTokens(address(this).balance);
        if (baseTokenBalance > 0) swapTokens(_stf.baseToken, baseTokenBalance);

        uint256 usdcBalance = IERC20(USDC).balanceOf(address(this));
        if (usdcBalance < 1) revert ZeroBalance();

        if (usdcBalance > _totalRaised) {
            uint256 profits = usdcBalance - _totalRaised;
            managerFee = (profits * vault.managerFee()) / 100e18;
            protocolFee = (profits * vault.protocolFee()) / 100e18;

            IERC20(USDC).transfer(manager, managerFee);
            IERC20(USDC).transfer(vault.treasury(), protocolFee);

            remaining = usdcBalance - (managerFee + protocolFee);
        } else {
            remaining = usdcBalance;
        }

        remainingBalance = remaining;

        IERC20(USDC).transfer(address(vault), remaining);
    }

    function withdraw(address receiver, bool isEth, address token, uint256 amount)
        external
        override
        onlyVault
    {
        if (isEth) {
            payable(receiver).transfer(amount);
        } else {
            IERC20(token).transfer(receiver, amount);
        }
    }

    /// @notice can be called for swapping ETH to USDC on GMX
    /// @dev internal function
    /// @param amount amount of ETH which needs to be swapped
    function swapEthToTokens(uint256 amount) internal {
        address[] memory _dex = reader.getDex();
        (uint256 amountOut,) = IGmxReader(_dex[4]).getAmountOut(IGmxVault(_dex[0]), WETH, USDC, amount);
        address[] memory path = new address[](2);
        path[0] = WETH;
        path[1] = USDC;
        IGmxRouter(_dex[1]).swapETHToTokens{value: amount}(path, amountOut, address(this));
    }

    /// @notice can be called for swapping any ERC20 token to USDC on GMX
    /// @dev internal function
    /// @param amount amount of the ERC20 token which needs to be swapped
    function swapTokens(address token, uint256 amount) internal {
        address[] memory _dex = reader.getDex();
        (uint256 amountOut,) = IGmxReader(_dex[4]).getAmountOut(IGmxVault(_dex[0]), token, USDC, amount);

        address[] memory path = new address[](2);
        path[0] = token;
        path[1] = USDC;

        IERC20(token).approve(_dex[1], amount);
        IGmxRouter(_dex[1]).swap(path, amount, amountOut, address(this));
    }

    /// @notice fallback function required when GMX sends back the `fee` in ETH when cancelling an order
    /// @dev fallback function does not do anything on receiving ETH
    receive() external payable {}
}

File 25 of 34 : Test.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.9.0;
pragma experimental ABIEncoderV2;

import "./Script.sol";
import "../lib/ds-test/src/test.sol";

// Wrappers around Cheatcodes to avoid footguns
abstract contract Test is DSTest, Script {
    using stdStorage for StdStorage;

    uint256 internal constant UINT256_MAX =
        115792089237316195423570985008687907853269984665640564039457584007913129639935;

    StdStorage internal stdstore;

    /*//////////////////////////////////////////////////////////////////////////
                                    STD-LOGS
    //////////////////////////////////////////////////////////////////////////*/

    event log_array(uint256[] val);
    event log_array(int256[] val);
    event log_array(address[] val);
    event log_named_array(string key, uint256[] val);
    event log_named_array(string key, int256[] val);
    event log_named_array(string key, address[] val);

    /*//////////////////////////////////////////////////////////////////////////
                                    STD-CHEATS
    //////////////////////////////////////////////////////////////////////////*/

    // Skip forward or rewind time by the specified number of seconds
    function skip(uint256 time) internal {
        vm.warp(block.timestamp + time);
    }

    function rewind(uint256 time) internal {
        vm.warp(block.timestamp - time);
    }

    // Setup a prank from an address that has some ether
    function hoax(address who) internal {
        vm.deal(who, 1 << 128);
        vm.prank(who);
    }

    function hoax(address who, uint256 give) internal {
        vm.deal(who, give);
        vm.prank(who);
    }

    function hoax(address who, address origin) internal {
        vm.deal(who, 1 << 128);
        vm.prank(who, origin);
    }

    function hoax(address who, address origin, uint256 give) internal {
        vm.deal(who, give);
        vm.prank(who, origin);
    }

    // Start perpetual prank from an address that has some ether
    function startHoax(address who) internal {
        vm.deal(who, 1 << 128);
        vm.startPrank(who);
    }

    function startHoax(address who, uint256 give) internal {
        vm.deal(who, give);
        vm.startPrank(who);
    }

    // Start perpetual prank from an address that has some ether
    // tx.origin is set to the origin parameter
    function startHoax(address who, address origin) internal {
        vm.deal(who, 1 << 128);
        vm.startPrank(who, origin);
    }

    function startHoax(address who, address origin, uint256 give) internal {
        vm.deal(who, give);
        vm.startPrank(who, origin);
    }

    function changePrank(address who) internal {
        vm.stopPrank();
        vm.startPrank(who);
    }

    // creates a labeled address and the corresponding private key
    function makeAddrAndKey(string memory name) internal returns(address addr, uint256 privateKey) {
        privateKey = uint256(keccak256(abi.encodePacked(name)));
        addr = vm.addr(privateKey);
        vm.label(addr, name);
    }

    // creates a labeled address
    function makeAddr(string memory name) internal returns(address addr) {
        (addr,) = makeAddrAndKey(name);
    }

    // DEPRECATED: Use `deal` instead
    function tip(address token, address to, uint256 give) internal {
        emit log_named_string("WARNING", "Test tip(address,address,uint256): The `tip` stdcheat has been deprecated. Use `deal` instead.");
        stdstore
            .target(token)
            .sig(0x70a08231)
            .with_key(to)
            .checked_write(give);
    }

    // The same as Vm's `deal`
    // Use the alternative signature for ERC20 tokens
    function deal(address to, uint256 give) internal {
        vm.deal(to, give);
    }

    // Set the balance of an account for any ERC20 token
    // Use the alternative signature to update `totalSupply`
    function deal(address token, address to, uint256 give) internal {
        deal(token, to, give, false);
    }

    function deal(address token, address to, uint256 give, bool adjust) internal {
        // get current balance
        (, bytes memory balData) = token.call(abi.encodeWithSelector(0x70a08231, to));
        uint256 prevBal = abi.decode(balData, (uint256));

        // update balance
        stdstore
            .target(token)
            .sig(0x70a08231)
            .with_key(to)
            .checked_write(give);

        // update total supply
        if(adjust){
            (, bytes memory totSupData) = token.call(abi.encodeWithSelector(0x18160ddd));
            uint256 totSup = abi.decode(totSupData, (uint256));
            if(give < prevBal) {
                totSup -= (prevBal - give);
            } else {
                totSup += (give - prevBal);
            }
            stdstore
                .target(token)
                .sig(0x18160ddd)
                .checked_write(totSup);
        }
    }

    function bound(uint256 x, uint256 min, uint256 max) internal virtual returns (uint256 result) {
        require(min <= max, "Test bound(uint256,uint256,uint256): Max is less than min.");

        uint256 size = max - min;

        if (size == 0)
        {
            result = min;
        }
        else if (size == UINT256_MAX)
        {
            result = x;
        }
        else
        {
            ++size; // make `max` inclusive
            uint256 mod = x % size;
            result = min + mod;
        }

        emit log_named_uint("Bound Result", result);
    }

    // Deploy a contract by fetching the contract bytecode from
    // the artifacts directory
    // e.g. `deployCode(code, abi.encode(arg1,arg2,arg3))`
    function deployCode(string memory what, bytes memory args)
        internal
        returns (address addr)
    {
        bytes memory bytecode = abi.encodePacked(vm.getCode(what), args);
        /// @solidity memory-safe-assembly
        assembly {
            addr := create(0, add(bytecode, 0x20), mload(bytecode))
        }

        require(
            addr != address(0),
            "Test deployCode(string,bytes): Deployment failed."
        );
    }

    function deployCode(string memory what)
        internal
        returns (address addr)
    {
        bytes memory bytecode = vm.getCode(what);
        /// @solidity memory-safe-assembly
        assembly {
            addr := create(0, add(bytecode, 0x20), mload(bytecode))
        }

        require(
            addr != address(0),
            "Test deployCode(string): Deployment failed."
        );
    }

    /// deploy contract with value on construction
    function deployCode(string memory what, bytes memory args, uint256 val)
        internal
        returns (address addr)
    {
        bytes memory bytecode = abi.encodePacked(vm.getCode(what), args);
        /// @solidity memory-safe-assembly
        assembly {
            addr := create(val, add(bytecode, 0x20), mload(bytecode))
        }

        require(
            addr != address(0),
            "Test deployCode(string,bytes,uint256): Deployment failed."
        );
    }

    function deployCode(string memory what, uint256 val)
        internal
        returns (address addr)
    {
        bytes memory bytecode = vm.getCode(what);
        /// @solidity memory-safe-assembly
        assembly {
            addr := create(val, add(bytecode, 0x20), mload(bytecode))
        }

        require(
            addr != address(0),
            "Test deployCode(string,uint256): Deployment failed."
        );
    }

    /*//////////////////////////////////////////////////////////////////////////
                                    STD-ASSERTIONS
    //////////////////////////////////////////////////////////////////////////*/

    function fail(string memory err) internal virtual {
        emit log_named_string("Error", err);
        fail();
    }

    function assertFalse(bool data) internal virtual {
        assertTrue(!data);
    }

    function assertFalse(bool data, string memory err) internal virtual {
        assertTrue(!data, err);
    }

    function assertEq(bool a, bool b) internal {
        if (a != b) {
            emit log                ("Error: a == b not satisfied [bool]");
            emit log_named_string   ("  Expected", b ? "true" : "false");
            emit log_named_string   ("    Actual", a ? "true" : "false");
            fail();
        }
    }

    function assertEq(bool a, bool b, string memory err) internal {
        if (a != b) {
            emit log_named_string("Error", err);
            assertEq(a, b);
        }
    }

    function assertEq(bytes memory a, bytes memory b) internal {
        assertEq0(a, b);
    }

    function assertEq(bytes memory a, bytes memory b, string memory err) internal {
        assertEq0(a, b, err);
    }

    function assertEq(uint256[] memory a, uint256[] memory b) internal {
        if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) {
            emit log("Error: a == b not satisfied [uint[]]");
            emit log_named_array("  Expected", b);
            emit log_named_array("    Actual", a);
            fail();
        }
    }

    function assertEq(int256[] memory a, int256[] memory b) internal {
        if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) {
            emit log("Error: a == b not satisfied [int[]]");
            emit log_named_array("  Expected", b);
            emit log_named_array("    Actual", a);
            fail();
        }
    }

    function assertEq(address[] memory a, address[] memory b) internal {
        if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) {
            emit log("Error: a == b not satisfied [address[]]");
            emit log_named_array("  Expected", b);
            emit log_named_array("    Actual", a);
            fail();
        }
    }

    function assertEq(uint256[] memory a, uint256[] memory b, string memory err) internal {
        if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) {
            emit log_named_string("Error", err);
            assertEq(a, b);
        }
    }

    function assertEq(int256[] memory a, int256[] memory b, string memory err) internal {
        if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) {
            emit log_named_string("Error", err);
            assertEq(a, b);
        }
    }


    function assertEq(address[] memory a, address[] memory b, string memory err) internal {
        if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) {
            emit log_named_string("Error", err);
            assertEq(a, b);
        }
    }

    function assertApproxEqAbs(
        uint256 a,
        uint256 b,
        uint256 maxDelta
    ) internal virtual {
        uint256 delta = stdMath.delta(a, b);

        if (delta > maxDelta) {
            emit log            ("Error: a ~= b not satisfied [uint]");
            emit log_named_uint ("  Expected", b);
            emit log_named_uint ("    Actual", a);
            emit log_named_uint (" Max Delta", maxDelta);
            emit log_named_uint ("     Delta", delta);
            fail();
        }
    }

    function assertApproxEqAbs(
        uint256 a,
        uint256 b,
        uint256 maxDelta,
        string memory err
    ) internal virtual {
        uint256 delta = stdMath.delta(a, b);

        if (delta > maxDelta) {
            emit log_named_string   ("Error", err);
            assertApproxEqAbs(a, b, maxDelta);
        }
    }

    function assertApproxEqAbs(
        int256 a,
        int256 b,
        uint256 maxDelta
    ) internal virtual {
        uint256 delta = stdMath.delta(a, b);

        if (delta > maxDelta) {
            emit log            ("Error: a ~= b not satisfied [int]");
            emit log_named_int  ("  Expected", b);
            emit log_named_int  ("    Actual", a);
            emit log_named_uint (" Max Delta", maxDelta);
            emit log_named_uint ("     Delta", delta);
            fail();
        }
    }

    function assertApproxEqAbs(
        int256 a,
        int256 b,
        uint256 maxDelta,
        string memory err
    ) internal virtual {
        uint256 delta = stdMath.delta(a, b);

        if (delta > maxDelta) {
            emit log_named_string   ("Error", err);
            assertApproxEqAbs(a, b, maxDelta);
        }
    }

    function assertApproxEqRel(
        uint256 a,
        uint256 b,
        uint256 maxPercentDelta // An 18 decimal fixed point number, where 1e18 == 100%
    ) internal virtual {
        if (b == 0) return assertEq(a, b); // If the expected is 0, actual must be too.

        uint256 percentDelta = stdMath.percentDelta(a, b);

        if (percentDelta > maxPercentDelta) {
            emit log                    ("Error: a ~= b not satisfied [uint]");
            emit log_named_uint         ("    Expected", b);
            emit log_named_uint         ("      Actual", a);
            emit log_named_decimal_uint (" Max % Delta", maxPercentDelta, 18);
            emit log_named_decimal_uint ("     % Delta", percentDelta, 18);
            fail();
        }
    }

    function assertApproxEqRel(
        uint256 a,
        uint256 b,
        uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100%
        string memory err
    ) internal virtual {
        if (b == 0) return assertEq(a, b, err); // If the expected is 0, actual must be too.

        uint256 percentDelta = stdMath.percentDelta(a, b);

        if (percentDelta > maxPercentDelta) {
            emit log_named_string       ("Error", err);
            assertApproxEqRel(a, b, maxPercentDelta);
        }
    }

    function assertApproxEqRel(
        int256 a,
        int256 b,
        uint256 maxPercentDelta
    ) internal virtual {
        if (b == 0) return assertEq(a, b); // If the expected is 0, actual must be too.

        uint256 percentDelta = stdMath.percentDelta(a, b);

        if (percentDelta > maxPercentDelta) {
            emit log                   ("Error: a ~= b not satisfied [int]");
            emit log_named_int         ("    Expected", b);
            emit log_named_int         ("      Actual", a);
            emit log_named_decimal_uint(" Max % Delta", maxPercentDelta, 18);
            emit log_named_decimal_uint("     % Delta", percentDelta, 18);
            fail();
        }
    }

    function assertApproxEqRel(
        int256 a,
        int256 b,
        uint256 maxPercentDelta,
        string memory err
    ) internal virtual {
        if (b == 0) return assertEq(a, b); // If the expected is 0, actual must be too.

        uint256 percentDelta = stdMath.percentDelta(a, b);

        if (percentDelta > maxPercentDelta) {
            emit log_named_string      ("Error", err);
            assertApproxEqRel(a, b, maxPercentDelta);
        }
    }

    /*//////////////////////////////////////////////////////////////
                              JSON PARSING
    //////////////////////////////////////////////////////////////*/

   // Data structures to parse Transaction objects from the broadcast artifact
   // that conform to EIP1559. The Raw structs is what is parsed from the JSON
   // and then converted to the one that is used by the user for better UX.

   struct RawTx1559 {
        string[] arguments;
        address contractAddress;
        string contractName;
        // json value name = function
        string functionSig;
        bytes32 hash;
        // json value name = tx
        RawTx1559Detail txDetail;
        // json value name = type
        string opcode;
    }

    struct RawTx1559Detail {
        AccessList[] accessList;
        bytes data;
        address from;
        bytes gas;
        bytes nonce;
        address to;
        bytes txType;
        bytes value;
    }

    struct Tx1559 {
        string[] arguments;
        address contractAddress;
        string contractName;
        string functionSig;
        bytes32 hash;
        Tx1559Detail txDetail;
        string opcode;
    }

    struct Tx1559Detail {
        AccessList[] accessList;
        bytes data;
        address from;
        uint256 gas;
        uint256 nonce;
        address to;
        uint256 txType;
        uint256 value;
    }

   // Data structures to parse Transaction objects from the broadcast artifact
   // that DO NOT conform to EIP1559. The Raw structs is what is parsed from the JSON
   // and then converted to the one that is used by the user for better UX.

    struct TxLegacy{
        string[] arguments;
        address contractAddress;
        string contractName;
        string functionSig;
        string hash;
        string opcode;
        TxDetailLegacy transaction;
    }

    struct TxDetailLegacy{
        AccessList[] accessList;
        uint256 chainId;
        bytes data;
        address from;
        uint256 gas;
        uint256 gasPrice;
        bytes32 hash;
        uint256 nonce;
        bytes1 opcode;
        bytes32 r;
        bytes32 s;
        uint256 txType;
        address to;
        uint8 v;
        uint256 value;
    }

    struct AccessList{
        address accessAddress;
        bytes32[] storageKeys;
    }

    // Data structures to parse Receipt objects from the broadcast artifact.
    // The Raw structs is what is parsed from the JSON
    // and then converted to the one that is used by the user for better UX.

    struct RawReceipt {
        bytes32 blockHash;
        bytes blockNumber;
        address contractAddress;
        bytes cumulativeGasUsed;
        bytes effectiveGasPrice;
        address from;
        bytes gasUsed;
        RawReceiptLog[] logs;
        bytes logsBloom;
        bytes status;
        address to;
        bytes32 transactionHash;
        bytes transactionIndex;
    }

    struct Receipt {
        bytes32 blockHash;
        uint256 blockNumber;
        address contractAddress;
        uint256 cumulativeGasUsed;
        uint256 effectiveGasPrice;
        address from;
        uint256 gasUsed;
        ReceiptLog[] logs;
        bytes logsBloom;
        uint256 status;
        address to;
        bytes32 transactionHash;
        uint256 transactionIndex;
    }

    // Data structures to parse the entire broadcast artifact, assuming the
    // transactions conform to EIP1559.

    struct EIP1559ScriptArtifact {
        string[] libraries;
        string path;
        string[] pending;
        Receipt[] receipts;
        uint256 timestamp;
        Tx1559[] transactions;
        TxReturn[] txReturns;
    }

    struct RawEIP1559ScriptArtifact {
        string[] libraries;
        string path;
        string[] pending;
        RawReceipt[] receipts;
        TxReturn[] txReturns;
        uint256 timestamp;
        RawTx1559[] transactions;
    }

    struct RawReceiptLog {
        // json value = address
        address logAddress;
        bytes32 blockHash;
        bytes blockNumber;
        bytes data;
        bytes logIndex;
        bool removed;
        bytes32[] topics;
        bytes32 transactionHash;
        bytes transactionIndex;
        bytes transactionLogIndex;
    }

    struct ReceiptLog {
        // json value = address
        address logAddress;
        bytes32 blockHash;
        uint256 blockNumber;
        bytes data;
        uint256 logIndex;
        bytes32[] topics;
        uint256 transactionIndex;
        uint256 transactionLogIndex;
        bool removed;
    }

    struct TxReturn {
        string internalType;
        string value;
    }


    function readEIP1559ScriptArtifact(string memory path)
        internal
        returns(EIP1559ScriptArtifact memory)
    {
        string memory data = vm.readFile(path);
        bytes memory parsedData = vm.parseJson(data);
        RawEIP1559ScriptArtifact memory rawArtifact = abi.decode(parsedData, (RawEIP1559ScriptArtifact));
        EIP1559ScriptArtifact memory artifact;
        artifact.libraries = rawArtifact.libraries;
        artifact.path = rawArtifact.path;
        artifact.timestamp = rawArtifact.timestamp;
        artifact.pending = rawArtifact.pending;
        artifact.txReturns = rawArtifact.txReturns;
        artifact.receipts = rawToConvertedReceipts(rawArtifact.receipts);
        artifact.transactions = rawToConvertedEIPTx1559s(rawArtifact.transactions);
        return artifact;
    }

    function rawToConvertedEIPTx1559s(RawTx1559[] memory rawTxs)
        internal pure
        returns (Tx1559[] memory)
    {
        Tx1559[] memory txs = new Tx1559[](rawTxs.length);
        for (uint i; i < rawTxs.length; i++) {
            txs[i] = rawToConvertedEIPTx1559(rawTxs[i]);
        }
        return txs;
    }

    function rawToConvertedEIPTx1559(RawTx1559 memory rawTx)
        internal pure
        returns (Tx1559 memory)
    {
        Tx1559 memory transaction;
        transaction.arguments = rawTx.arguments;
        transaction.contractName = rawTx.contractName;
        transaction.functionSig = rawTx.functionSig;
        transaction.hash= rawTx.hash;
        transaction.txDetail = rawToConvertedEIP1559Detail(rawTx.txDetail);
        transaction.opcode= rawTx.opcode;
        return transaction;
    }

    function rawToConvertedEIP1559Detail(RawTx1559Detail memory rawDetail)
        internal pure
        returns (Tx1559Detail memory)
    {
        Tx1559Detail memory txDetail;
        txDetail.data = rawDetail.data;
        txDetail.from = rawDetail.from;
        txDetail.to = rawDetail.to;
        txDetail.nonce = bytesToUint(rawDetail.nonce);
        txDetail.txType = bytesToUint(rawDetail.txType);
        txDetail.value = bytesToUint(rawDetail.value);
        txDetail.gas = bytesToUint(rawDetail.gas);
        txDetail.accessList = rawDetail.accessList;
        return txDetail;

    }

    function readTx1559s(string memory path)
        internal
        returns (Tx1559[] memory)
    {
        string memory deployData = vm.readFile(path);
        bytes memory parsedDeployData =
            vm.parseJson(deployData, ".transactions");
        RawTx1559[] memory rawTxs = abi.decode(parsedDeployData, (RawTx1559[]));
        return rawToConvertedEIPTx1559s(rawTxs);
    }


    function readTx1559(string memory path, uint256 index)
        internal
        returns (Tx1559 memory)
    {
        string memory deployData = vm.readFile(path);
        string memory key = string(abi.encodePacked(".transactions[",vm.toString(index), "]"));
        bytes memory parsedDeployData =
            vm.parseJson(deployData, key);
        RawTx1559 memory rawTx = abi.decode(parsedDeployData, (RawTx1559));
        return rawToConvertedEIPTx1559(rawTx);
    }


    // Analogous to readTransactions, but for receipts.
    function readReceipts(string memory path)
        internal
        returns (Receipt[] memory)
    {
        string memory deployData = vm.readFile(path);
        bytes memory parsedDeployData = vm.parseJson(deployData, ".receipts");
        RawReceipt[] memory rawReceipts = abi.decode(parsedDeployData, (RawReceipt[]));
        return rawToConvertedReceipts(rawReceipts);
    }

    function readReceipt(string memory path, uint index)
        internal
        returns (Receipt memory)
    {
        string memory deployData = vm.readFile(path);
        string memory key = string(abi.encodePacked(".receipts[",vm.toString(index), "]"));
        bytes memory parsedDeployData = vm.parseJson(deployData, key);
        RawReceipt memory rawReceipt = abi.decode(parsedDeployData, (RawReceipt));
        return rawToConvertedReceipt(rawReceipt);
    }

    function rawToConvertedReceipts(RawReceipt[] memory rawReceipts)
        internal pure
        returns(Receipt[] memory)
    {
        Receipt[] memory receipts = new Receipt[](rawReceipts.length);
        for (uint i; i < rawReceipts.length; i++) {
            receipts[i] = rawToConvertedReceipt(rawReceipts[i]);
        }
        return receipts;
    }

    function rawToConvertedReceipt(RawReceipt memory rawReceipt)
        internal pure
        returns(Receipt memory)
    {
        Receipt memory receipt;
        receipt.blockHash = rawReceipt.blockHash;
        receipt.to = rawReceipt.to;
        receipt.from = rawReceipt.from;
        receipt.contractAddress = rawReceipt.contractAddress;
        receipt.effectiveGasPrice = bytesToUint(rawReceipt.effectiveGasPrice);
        receipt.cumulativeGasUsed= bytesToUint(rawReceipt.cumulativeGasUsed);
        receipt.gasUsed = bytesToUint(rawReceipt.gasUsed);
        receipt.status = bytesToUint(rawReceipt.status);
        receipt.transactionIndex = bytesToUint(rawReceipt.transactionIndex);
        receipt.blockNumber = bytesToUint(rawReceipt.blockNumber);
        receipt.logs = rawToConvertedReceiptLogs(rawReceipt.logs);
        receipt.logsBloom = rawReceipt.logsBloom;
        receipt.transactionHash = rawReceipt.transactionHash;
        return receipt;
    }

    function rawToConvertedReceiptLogs(RawReceiptLog[] memory rawLogs)
        internal pure
        returns (ReceiptLog[] memory)
    {
        ReceiptLog[] memory logs = new ReceiptLog[](rawLogs.length);
        for (uint i; i < rawLogs.length; i++) {
            logs[i].logAddress = rawLogs[i].logAddress;
            logs[i].blockHash = rawLogs[i].blockHash;
            logs[i].blockNumber = bytesToUint(rawLogs[i].blockNumber);
            logs[i].data = rawLogs[i].data;
            logs[i].logIndex = bytesToUint(rawLogs[i].logIndex);
            logs[i].topics = rawLogs[i].topics;
            logs[i].transactionIndex = bytesToUint(rawLogs[i].transactionIndex);
            logs[i].transactionLogIndex = bytesToUint(rawLogs[i].transactionLogIndex);
            logs[i].removed = rawLogs[i].removed;
        }
        return logs;

    }

    function bytesToUint(bytes memory b) internal pure returns (uint256){
            uint256 number;
            for (uint i=0; i < b.length; i++) {
                number = number + uint(uint8(b[i]))*(2**(8*(b.length-(i+1))));
            }
        return number;
    }

}

/*//////////////////////////////////////////////////////////////////////////
                                STD-ERRORS
//////////////////////////////////////////////////////////////////////////*/

library stdError {
    bytes public constant assertionError = abi.encodeWithSignature("Panic(uint256)", 0x01);
    bytes public constant arithmeticError = abi.encodeWithSignature("Panic(uint256)", 0x11);
    bytes public constant divisionError = abi.encodeWithSignature("Panic(uint256)", 0x12);
    bytes public constant enumConversionError = abi.encodeWithSignature("Panic(uint256)", 0x21);
    bytes public constant encodeStorageError = abi.encodeWithSignature("Panic(uint256)", 0x22);
    bytes public constant popError = abi.encodeWithSignature("Panic(uint256)", 0x31);
    bytes public constant indexOOBError = abi.encodeWithSignature("Panic(uint256)", 0x32);
    bytes public constant memOverflowError = abi.encodeWithSignature("Panic(uint256)", 0x41);
    bytes public constant zeroVarError = abi.encodeWithSignature("Panic(uint256)", 0x51);
    // DEPRECATED: Use Vm's `expectRevert` without any arguments instead
    bytes public constant lowLevelError = bytes(""); // `0x`
}

/*//////////////////////////////////////////////////////////////////////////
                                STD-STORAGE
//////////////////////////////////////////////////////////////////////////*/

struct StdStorage {
    mapping (address => mapping(bytes4 => mapping(bytes32 => uint256))) slots;
    mapping (address => mapping(bytes4 =>  mapping(bytes32 => bool))) finds;

    bytes32[] _keys;
    bytes4 _sig;
    uint256 _depth;
    address _target;
    bytes32 _set;
}

library stdStorage {
    event SlotFound(address who, bytes4 fsig, bytes32 keysHash, uint slot);
    event WARNING_UninitedSlot(address who, uint slot);

    uint256 private constant UINT256_MAX = 115792089237316195423570985008687907853269984665640564039457584007913129639935;
    int256 private constant INT256_MAX = 57896044618658097711785492504343953926634992332820282019728792003956564819967;

    Vm private constant vm_std_store = Vm(address(uint160(uint256(keccak256('hevm cheat code')))));

    function sigs(
        string memory sigStr
    )
        internal
        pure
        returns (bytes4)
    {
        return bytes4(keccak256(bytes(sigStr)));
    }

    /// @notice find an arbitrary storage slot given a function sig, input data, address of the contract and a value to check against
    // slot complexity:
    //  if flat, will be bytes32(uint256(uint));
    //  if map, will be keccak256(abi.encode(key, uint(slot)));
    //  if deep map, will be keccak256(abi.encode(key1, keccak256(abi.encode(key0, uint(slot)))));
    //  if map struct, will be bytes32(uint256(keccak256(abi.encode(key1, keccak256(abi.encode(key0, uint(slot)))))) + structFieldDepth);
    function find(
        StdStorage storage self
    )
        internal
        returns (uint256)
    {
        address who = self._target;
        bytes4 fsig = self._sig;
        uint256 field_depth = self._depth;
        bytes32[] memory ins = self._keys;

        // calldata to test against
        if (self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]) {
            return self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))];
        }
        bytes memory cald = abi.encodePacked(fsig, flatten(ins));
        vm_std_store.record();
        bytes32 fdat;
        {
            (, bytes memory rdat) = who.staticcall(cald);
            fdat = bytesToBytes32(rdat, 32*field_depth);
        }

        (bytes32[] memory reads, ) = vm_std_store.accesses(address(who));
        if (reads.length == 1) {
            bytes32 curr = vm_std_store.load(who, reads[0]);
            if (curr == bytes32(0)) {
                emit WARNING_UninitedSlot(who, uint256(reads[0]));
            }
            if (fdat != curr) {
                require(false, "stdStorage find(StdStorage): Packed slot. This would cause dangerous overwriting and currently isn't supported.");
            }
            emit SlotFound(who, fsig, keccak256(abi.encodePacked(ins, field_depth)), uint256(reads[0]));
            self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = uint256(reads[0]);
            self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = true;
        } else if (reads.length > 1) {
            for (uint256 i = 0; i < reads.length; i++) {
                bytes32 prev = vm_std_store.load(who, reads[i]);
                if (prev == bytes32(0)) {
                    emit WARNING_UninitedSlot(who, uint256(reads[i]));
                }
                // store
                vm_std_store.store(who, reads[i], bytes32(hex"1337"));
                bool success;
                bytes memory rdat;
                {
                    (success, rdat) = who.staticcall(cald);
                    fdat = bytesToBytes32(rdat, 32*field_depth);
                }

                if (success && fdat == bytes32(hex"1337")) {
                    // we found which of the slots is the actual one
                    emit SlotFound(who, fsig, keccak256(abi.encodePacked(ins, field_depth)), uint256(reads[i]));
                    self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = uint256(reads[i]);
                    self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = true;
                    vm_std_store.store(who, reads[i], prev);
                    break;
                }
                vm_std_store.store(who, reads[i], prev);
            }
        } else {
            require(false, "stdStorage find(StdStorage): No storage use detected for target.");
        }

        require(self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))], "stdStorage find(StdStorage): Slot(s) not found.");

        delete self._target;
        delete self._sig;
        delete self._keys;
        delete self._depth;

        return self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))];
    }

    function target(StdStorage storage self, address _target) internal returns (StdStorage storage) {
        self._target = _target;
        return self;
    }

    function sig(StdStorage storage self, bytes4 _sig) internal returns (StdStorage storage) {
        self._sig = _sig;
        return self;
    }

    function sig(StdStorage storage self, string memory _sig) internal returns (StdStorage storage) {
        self._sig = sigs(_sig);
        return self;
    }

    function with_key(StdStorage storage self, address who) internal returns (StdStorage storage) {
        self._keys.push(bytes32(uint256(uint160(who))));
        return self;
    }

    function with_key(StdStorage storage self, uint256 amt) internal returns (StdStorage storage) {
        self._keys.push(bytes32(amt));
        return self;
    }
    function with_key(StdStorage storage self, bytes32 key) internal returns (StdStorage storage) {
        self._keys.push(key);
        return self;
    }

    function depth(StdStorage storage self, uint256 _depth) internal returns (StdStorage storage) {
        self._depth = _depth;
        return self;
    }

    function checked_write(StdStorage storage self, address who) internal {
        checked_write(self, bytes32(uint256(uint160(who))));
    }

    function checked_write(StdStorage storage self, uint256 amt) internal {
        checked_write(self, bytes32(amt));
    }

    function checked_write(StdStorage storage self, bool write) internal {
        bytes32 t;
        /// @solidity memory-safe-assembly
        assembly {
            t := write
        }
        checked_write(self, t);
    }

    function checked_write(
        StdStorage storage self,
        bytes32 set
    ) internal {
        address who = self._target;
        bytes4 fsig = self._sig;
        uint256 field_depth = self._depth;
        bytes32[] memory ins = self._keys;

        bytes memory cald = abi.encodePacked(fsig, flatten(ins));
        if (!self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]) {
            find(self);
        }
        bytes32 slot = bytes32(self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]);

        bytes32 fdat;
        {
            (, bytes memory rdat) = who.staticcall(cald);
            fdat = bytesToBytes32(rdat, 32*field_depth);
        }
        bytes32 curr = vm_std_store.load(who, slot);

        if (fdat != curr) {
            require(false, "stdStorage find(StdStorage): Packed slot. This would cause dangerous overwriting and currently isn't supported.");
        }
        vm_std_store.store(who, slot, set);
        delete self._target;
        delete self._sig;
        delete self._keys;
        delete self._depth;
    }

    function read(StdStorage storage self) private returns (bytes memory) {
        address t = self._target;
        uint256 s = find(self);
        return abi.encode(vm_std_store.load(t, bytes32(s)));
    }

    function read_bytes32(StdStorage storage self) internal returns (bytes32) {
        return abi.decode(read(self), (bytes32));
    }


    function read_bool(StdStorage storage self) internal returns (bool) {
        int256 v = read_int(self);
        if (v == 0) return false;
        if (v == 1) return true;
        revert("stdStorage read_bool(StdStorage): Cannot decode. Make sure you are reading a bool.");
    }

    function read_address(StdStorage storage self) internal returns (address) {
        return abi.decode(read(self), (address));
    }

    function read_uint(StdStorage storage self) internal returns (uint256) {
        return abi.decode(read(self), (uint256));
    }

    function read_int(StdStorage storage self) internal returns (int256) {
        return abi.decode(read(self), (int256));
    }

    function bytesToBytes32(bytes memory b, uint offset) public pure returns (bytes32) {
        bytes32 out;

        uint256 max = b.length > 32 ? 32 : b.length;
        for (uint i = 0; i < max; i++) {
            out |= bytes32(b[offset + i] & 0xFF) >> (i * 8);
        }
        return out;
    }

    function flatten(bytes32[] memory b) private pure returns (bytes memory)
    {
        bytes memory result = new bytes(b.length * 32);
        for (uint256 i = 0; i < b.length; i++) {
            bytes32 k = b[i];
            /// @solidity memory-safe-assembly
            assembly {
                mstore(add(result, add(32, mul(32, i))), k)
            }
        }

        return result;
    }



}


/*//////////////////////////////////////////////////////////////////////////
                                STD-MATH
//////////////////////////////////////////////////////////////////////////*/

library stdMath {
    int256 private constant INT256_MIN = -57896044618658097711785492504343953926634992332820282019728792003956564819968;

    function abs(int256 a) internal pure returns (uint256) {
        // Required or it will fail when `a = type(int256).min`
        if (a == INT256_MIN)
            return 57896044618658097711785492504343953926634992332820282019728792003956564819968;

        return uint256(a > 0 ? a : -a);
    }

    function delta(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b
            ? a - b
            : b - a;
    }

    function delta(int256 a, int256 b) internal pure returns (uint256) {
        // a and b are of the same sign
        // this works thanks to two's complement, the left-most bit is the sign bit
        if ((a ^ b) > -1) {
            return delta(abs(a), abs(b));
        }

        // a and b are of opposite signs
        return abs(a) + abs(b);
    }

    function percentDelta(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 absDelta = delta(a, b);

        return absDelta * 1e18 / b;
    }

    function percentDelta(int256 a, int256 b) internal pure returns (uint256) {
        uint256 absDelta = delta(a, b);
        uint256 absB = abs(b);

        return absDelta * 1e18 / absB;
    }
}

File 26 of 34 : IGmxRouter.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

interface IGmxRouter {
    function addPlugin(address _plugin) external;

    function pluginTransfer(address _token, address _account, address _receiver, uint256 _amount) external;

    function pluginIncreasePosition(
        address _account,
        address _collateralToken,
        address _indexToken,
        uint256 _sizeDelta,
        bool _isLong
    ) external;

    function pluginDecreasePosition(
        address _account,
        address _collateralToken,
        address _indexToken,
        uint256 _collateralDelta,
        uint256 _sizeDelta,
        bool _isLong,
        address _receiver
    ) external returns (uint256);

    function swap(address[] memory _path, uint256 _amountIn, uint256 _minOut, address _receiver) external;

    function directPoolDeposit(address _token, uint256 _amount) external;

    function approvePlugin(address) external;

    function decreasePosition(
        address _collateralToken,
        address _indexToken,
        uint256 _collateralDelta,
        uint256 _sizeDelta,
        bool _isLong,
        address _receiver,
        uint256 _price
    ) external;

    function swapETHToTokens(address[] memory _path, uint256 _minOut, address _receiver) external payable;
}

File 27 of 34 : IGmxPositionRouter.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

interface IGmxPositionRouter {

    function executeIncreasePosition(bytes32 _key, address payable _executionFeeReceiver) external returns (bool);

    function executeDecreasePosition(bytes32 _key, address payable _executionFeeReceiver) external returns (bool);

    function createIncreasePosition(
        address[] memory _path,
        address _indexToken,
        uint256 _amountIn,
        uint256 _minOut,
        uint256 _sizeDelta,
        bool _isLong,
        uint256 _acceptablePrice,
        uint256 _executionFee,
        bytes32 _referralCode,
        address _callbackTarget
    ) external payable returns (bytes32);

    function createDecreasePosition(
        address[] memory _path,
        address _indexToken,
        uint256 _collateralDelta,
        uint256 _sizeDelta,
        bool _isLong,
        address _receiver,
        uint256 _acceptablePrice,
        uint256 _minOut,
        uint256 _executionFee,
        bool _withdrawETH,
        address _callbackTarget
    ) external payable returns (bytes32);

    function minExecutionFee() external view returns (uint256);

    function setPositionKeeper(address _account, bool _isActive) external;

    function getRequestKey(address _account, uint256 _index) external pure returns (bytes32);

    function getDecreasePositionRequestPath(bytes32 _key) external view returns (address[] memory);

    function cancelIncreasePosition(bytes32 _key, address payable _executionFeeReceiver) external returns (bool);

    function cancelDecreasePosition(bytes32 _key, address payable _executionFeeReceiver) external returns (bool);

    function executeIncreasePositions(uint256 _count, address payable _executionFeeReceiver) external;

    function executeDecreasePositions(uint256 _count, address payable _executionFeeReceiver) external;

    function increasePositionRequestKeysStart() external returns (uint256);

    function decreasePositionRequestKeysStart() external returns (uint256);
}

File 28 of 34 : IGmxOrderBook.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

interface IGmxOrderBook {
    function getSwapOrder(address _account, uint256 _orderIndex)
        external
        view
        returns (
            address path0,
            address path1,
            address path2,
            uint256 amountIn,
            uint256 minOut,
            uint256 triggerRatio,
            bool triggerAboveThreshold,
            bool shouldUnwrap,
            uint256 executionFee
        );

    function getIncreaseOrder(address _account, uint256 _orderIndex)
        external
        view
        returns (
            address purchaseToken,
            uint256 purchaseTokenAmount,
            address collateralToken,
            address indexToken,
            uint256 sizeDelta,
            bool isLong,
            uint256 triggerPrice,
            bool triggerAboveThreshold,
            uint256 executionFee
        );

    function getDecreaseOrder(address _account, uint256 _orderIndex)
        external
        view
        returns (
            address collateralToken,
            uint256 collateralDelta,
            address indexToken,
            uint256 sizeDelta,
            bool isLong,
            uint256 triggerPrice,
            bool triggerAboveThreshold,
            uint256 executionFee
        );

    function executeSwapOrder(address, uint256, address payable) external;
    function executeDecreaseOrder(address, uint256, address payable) external;
    function executeIncreaseOrder(address, uint256, address payable) external;

    function createIncreaseOrder(
        address[] memory _path,
        uint256 _amountIn,
        address _indexToken,
        uint256 _minOut,
        uint256 _sizeDelta,
        address _collateralToken,
        bool _isLong,
        uint256 _triggerPrice,
        bool _triggerAboveThreshold,
        uint256 _executionFee,
        bool _shouldWrap
    ) external payable;

    function createDecreaseOrder(
        address _indexToken,
        uint256 _sizeDelta,
        address _collateralToken,
        uint256 _collateralDelta,
        bool _isLong,
        uint256 _triggerPrice,
        bool _triggerAboveThreshold
    ) external payable;

    function increaseOrdersIndex(address) external view returns (uint256);
    function decreaseOrdersIndex(address) external view returns (uint256);

    function validatePositionOrderPrice(
        bool _triggerAboveThreshold,
        uint256 _triggerPrice,
        address _indexToken,
        bool _maximizePrice,
        bool _raise
    ) external view returns (uint256, bool);

    function updateIncreaseOrder(
        uint256 _orderIndex,
        uint256 _sizeDelta,
        uint256 _triggerPrice,
        bool _triggerAboveThreshold
    ) external;

    function updateDecreaseOrder(
        uint256 _orderIndex,
        uint256 _collateralDelta,
        uint256 _sizeDelta,
        uint256 _triggerPrice,
        bool _triggerAboveThreshold
    ) external;

    function cancelIncreaseOrder(uint256 _orderIndex) external;

    function cancelDecreaseOrder(uint256 _orderIndex) external;
}

File 29 of 34 : Script.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.9.0;

import "./console.sol";
import "./console2.sol";
import "./StdJson.sol";

abstract contract Script {
    bool public IS_SCRIPT = true;
    address constant private VM_ADDRESS =
        address(bytes20(uint160(uint256(keccak256('hevm cheat code')))));

    Vm public constant vm = Vm(VM_ADDRESS);

    /// @dev Compute the address a contract will be deployed at for a given deployer address and nonce
    /// @notice adapated from Solmate implementation (https://github.com/transmissions11/solmate/blob/main/src/utils/LibRLP.sol)
    function computeCreateAddress(address deployer, uint256 nonce) internal pure returns (address) {
        // The integer zero is treated as an empty byte string, and as a result it only has a length prefix, 0x80, computed via 0x80 + 0.
        // A one byte integer uses its own value as its length prefix, there is no additional "0x80 + length" prefix that comes before it.
        if (nonce == 0x00)             return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd6), bytes1(0x94), deployer, bytes1(0x80))));
        if (nonce <= 0x7f)             return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd6), bytes1(0x94), deployer, uint8(nonce))));

        // Nonces greater than 1 byte all follow a consistent encoding scheme, where each value is preceded by a prefix of 0x80 + length.
        if (nonce <= 2**8 - 1)  return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd7), bytes1(0x94), deployer, bytes1(0x81), uint8(nonce))));
        if (nonce <= 2**16 - 1) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd8), bytes1(0x94), deployer, bytes1(0x82), uint16(nonce))));
        if (nonce <= 2**24 - 1) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd9), bytes1(0x94), deployer, bytes1(0x83), uint24(nonce))));

        // More details about RLP encoding can be found here: https://eth.wiki/fundamentals/rlp
        // 0xda = 0xc0 (short RLP prefix) + 0x16 (length of: 0x94 ++ proxy ++ 0x84 ++ nonce)
        // 0x94 = 0x80 + 0x14 (0x14 = the length of an address, 20 bytes, in hex)
        // 0x84 = 0x80 + 0x04 (0x04 = the bytes length of the nonce, 4 bytes, in hex)
        // We assume nobody can have a nonce large enough to require more than 32 bytes.
        return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xda), bytes1(0x94), deployer, bytes1(0x84), uint32(nonce))));
    }

    function addressFromLast20Bytes(bytes32 bytesValue) internal pure returns (address) {
        return address(uint160(uint256(bytesValue)));
    }
}

File 30 of 34 : test.sol
// SPDX-License-Identifier: GPL-3.0-or-later

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

pragma solidity >=0.5.0;

contract DSTest {
    event log                    (string);
    event logs                   (bytes);

    event log_address            (address);
    event log_bytes32            (bytes32);
    event log_int                (int);
    event log_uint               (uint);
    event log_bytes              (bytes);
    event log_string             (string);

    event log_named_address      (string key, address val);
    event log_named_bytes32      (string key, bytes32 val);
    event log_named_decimal_int  (string key, int val, uint decimals);
    event log_named_decimal_uint (string key, uint val, uint decimals);
    event log_named_int          (string key, int val);
    event log_named_uint         (string key, uint val);
    event log_named_bytes        (string key, bytes val);
    event log_named_string       (string key, string val);

    bool public IS_TEST = true;
    bool private _failed;

    address constant HEVM_ADDRESS =
        address(bytes20(uint160(uint256(keccak256('hevm cheat code')))));

    modifier mayRevert() { _; }
    modifier testopts(string memory) { _; }

    function failed() public returns (bool) {
        if (_failed) {
            return _failed;
        } else {
            bool globalFailed = false;
            if (hasHEVMContext()) {
                (, bytes memory retdata) = HEVM_ADDRESS.call(
                    abi.encodePacked(
                        bytes4(keccak256("load(address,bytes32)")),
                        abi.encode(HEVM_ADDRESS, bytes32("failed"))
                    )
                );
                globalFailed = abi.decode(retdata, (bool));
            }
            return globalFailed;
        }
    } 

    function fail() internal {
        if (hasHEVMContext()) {
            (bool status, ) = HEVM_ADDRESS.call(
                abi.encodePacked(
                    bytes4(keccak256("store(address,bytes32,bytes32)")),
                    abi.encode(HEVM_ADDRESS, bytes32("failed"), bytes32(uint256(0x01)))
                )
            );
            status; // Silence compiler warnings
        }
        _failed = true;
    }

    function hasHEVMContext() internal view returns (bool) {
        uint256 hevmCodeSize = 0;
        assembly {
            hevmCodeSize := extcodesize(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D)
        }
        return hevmCodeSize > 0;
    }

    modifier logs_gas() {
        uint startGas = gasleft();
        _;
        uint endGas = gasleft();
        emit log_named_uint("gas", startGas - endGas);
    }

    function assertTrue(bool condition) internal {
        if (!condition) {
            emit log("Error: Assertion Failed");
            fail();
        }
    }

    function assertTrue(bool condition, string memory err) internal {
        if (!condition) {
            emit log_named_string("Error", err);
            assertTrue(condition);
        }
    }

    function assertEq(address a, address b) internal {
        if (a != b) {
            emit log("Error: a == b not satisfied [address]");
            emit log_named_address("  Expected", b);
            emit log_named_address("    Actual", a);
            fail();
        }
    }
    function assertEq(address a, address b, string memory err) internal {
        if (a != b) {
            emit log_named_string ("Error", err);
            assertEq(a, b);
        }
    }

    function assertEq(bytes32 a, bytes32 b) internal {
        if (a != b) {
            emit log("Error: a == b not satisfied [bytes32]");
            emit log_named_bytes32("  Expected", b);
            emit log_named_bytes32("    Actual", a);
            fail();
        }
    }
    function assertEq(bytes32 a, bytes32 b, string memory err) internal {
        if (a != b) {
            emit log_named_string ("Error", err);
            assertEq(a, b);
        }
    }
    function assertEq32(bytes32 a, bytes32 b) internal {
        assertEq(a, b);
    }
    function assertEq32(bytes32 a, bytes32 b, string memory err) internal {
        assertEq(a, b, err);
    }

    function assertEq(int a, int b) internal {
        if (a != b) {
            emit log("Error: a == b not satisfied [int]");
            emit log_named_int("  Expected", b);
            emit log_named_int("    Actual", a);
            fail();
        }
    }
    function assertEq(int a, int b, string memory err) internal {
        if (a != b) {
            emit log_named_string("Error", err);
            assertEq(a, b);
        }
    }
    function assertEq(uint a, uint b) internal {
        if (a != b) {
            emit log("Error: a == b not satisfied [uint]");
            emit log_named_uint("  Expected", b);
            emit log_named_uint("    Actual", a);
            fail();
        }
    }
    function assertEq(uint a, uint b, string memory err) internal {
        if (a != b) {
            emit log_named_string("Error", err);
            assertEq(a, b);
        }
    }
    function assertEqDecimal(int a, int b, uint decimals) internal {
        if (a != b) {
            emit log("Error: a == b not satisfied [decimal int]");
            emit log_named_decimal_int("  Expected", b, decimals);
            emit log_named_decimal_int("    Actual", a, decimals);
            fail();
        }
    }
    function assertEqDecimal(int a, int b, uint decimals, string memory err) internal {
        if (a != b) {
            emit log_named_string("Error", err);
            assertEqDecimal(a, b, decimals);
        }
    }
    function assertEqDecimal(uint a, uint b, uint decimals) internal {
        if (a != b) {
            emit log("Error: a == b not satisfied [decimal uint]");
            emit log_named_decimal_uint("  Expected", b, decimals);
            emit log_named_decimal_uint("    Actual", a, decimals);
            fail();
        }
    }
    function assertEqDecimal(uint a, uint b, uint decimals, string memory err) internal {
        if (a != b) {
            emit log_named_string("Error", err);
            assertEqDecimal(a, b, decimals);
        }
    }

    function assertGt(uint a, uint b) internal {
        if (a <= b) {
            emit log("Error: a > b not satisfied [uint]");
            emit log_named_uint("  Value a", a);
            emit log_named_uint("  Value b", b);
            fail();
        }
    }
    function assertGt(uint a, uint b, string memory err) internal {
        if (a <= b) {
            emit log_named_string("Error", err);
            assertGt(a, b);
        }
    }
    function assertGt(int a, int b) internal {
        if (a <= b) {
            emit log("Error: a > b not satisfied [int]");
            emit log_named_int("  Value a", a);
            emit log_named_int("  Value b", b);
            fail();
        }
    }
    function assertGt(int a, int b, string memory err) internal {
        if (a <= b) {
            emit log_named_string("Error", err);
            assertGt(a, b);
        }
    }
    function assertGtDecimal(int a, int b, uint decimals) internal {
        if (a <= b) {
            emit log("Error: a > b not satisfied [decimal int]");
            emit log_named_decimal_int("  Value a", a, decimals);
            emit log_named_decimal_int("  Value b", b, decimals);
            fail();
        }
    }
    function assertGtDecimal(int a, int b, uint decimals, string memory err) internal {
        if (a <= b) {
            emit log_named_string("Error", err);
            assertGtDecimal(a, b, decimals);
        }
    }
    function assertGtDecimal(uint a, uint b, uint decimals) internal {
        if (a <= b) {
            emit log("Error: a > b not satisfied [decimal uint]");
            emit log_named_decimal_uint("  Value a", a, decimals);
            emit log_named_decimal_uint("  Value b", b, decimals);
            fail();
        }
    }
    function assertGtDecimal(uint a, uint b, uint decimals, string memory err) internal {
        if (a <= b) {
            emit log_named_string("Error", err);
            assertGtDecimal(a, b, decimals);
        }
    }

    function assertGe(uint a, uint b) internal {
        if (a < b) {
            emit log("Error: a >= b not satisfied [uint]");
            emit log_named_uint("  Value a", a);
            emit log_named_uint("  Value b", b);
            fail();
        }
    }
    function assertGe(uint a, uint b, string memory err) internal {
        if (a < b) {
            emit log_named_string("Error", err);
            assertGe(a, b);
        }
    }
    function assertGe(int a, int b) internal {
        if (a < b) {
            emit log("Error: a >= b not satisfied [int]");
            emit log_named_int("  Value a", a);
            emit log_named_int("  Value b", b);
            fail();
        }
    }
    function assertGe(int a, int b, string memory err) internal {
        if (a < b) {
            emit log_named_string("Error", err);
            assertGe(a, b);
        }
    }
    function assertGeDecimal(int a, int b, uint decimals) internal {
        if (a < b) {
            emit log("Error: a >= b not satisfied [decimal int]");
            emit log_named_decimal_int("  Value a", a, decimals);
            emit log_named_decimal_int("  Value b", b, decimals);
            fail();
        }
    }
    function assertGeDecimal(int a, int b, uint decimals, string memory err) internal {
        if (a < b) {
            emit log_named_string("Error", err);
            assertGeDecimal(a, b, decimals);
        }
    }
    function assertGeDecimal(uint a, uint b, uint decimals) internal {
        if (a < b) {
            emit log("Error: a >= b not satisfied [decimal uint]");
            emit log_named_decimal_uint("  Value a", a, decimals);
            emit log_named_decimal_uint("  Value b", b, decimals);
            fail();
        }
    }
    function assertGeDecimal(uint a, uint b, uint decimals, string memory err) internal {
        if (a < b) {
            emit log_named_string("Error", err);
            assertGeDecimal(a, b, decimals);
        }
    }

    function assertLt(uint a, uint b) internal {
        if (a >= b) {
            emit log("Error: a < b not satisfied [uint]");
            emit log_named_uint("  Value a", a);
            emit log_named_uint("  Value b", b);
            fail();
        }
    }
    function assertLt(uint a, uint b, string memory err) internal {
        if (a >= b) {
            emit log_named_string("Error", err);
            assertLt(a, b);
        }
    }
    function assertLt(int a, int b) internal {
        if (a >= b) {
            emit log("Error: a < b not satisfied [int]");
            emit log_named_int("  Value a", a);
            emit log_named_int("  Value b", b);
            fail();
        }
    }
    function assertLt(int a, int b, string memory err) internal {
        if (a >= b) {
            emit log_named_string("Error", err);
            assertLt(a, b);
        }
    }
    function assertLtDecimal(int a, int b, uint decimals) internal {
        if (a >= b) {
            emit log("Error: a < b not satisfied [decimal int]");
            emit log_named_decimal_int("  Value a", a, decimals);
            emit log_named_decimal_int("  Value b", b, decimals);
            fail();
        }
    }
    function assertLtDecimal(int a, int b, uint decimals, string memory err) internal {
        if (a >= b) {
            emit log_named_string("Error", err);
            assertLtDecimal(a, b, decimals);
        }
    }
    function assertLtDecimal(uint a, uint b, uint decimals) internal {
        if (a >= b) {
            emit log("Error: a < b not satisfied [decimal uint]");
            emit log_named_decimal_uint("  Value a", a, decimals);
            emit log_named_decimal_uint("  Value b", b, decimals);
            fail();
        }
    }
    function assertLtDecimal(uint a, uint b, uint decimals, string memory err) internal {
        if (a >= b) {
            emit log_named_string("Error", err);
            assertLtDecimal(a, b, decimals);
        }
    }

    function assertLe(uint a, uint b) internal {
        if (a > b) {
            emit log("Error: a <= b not satisfied [uint]");
            emit log_named_uint("  Value a", a);
            emit log_named_uint("  Value b", b);
            fail();
        }
    }
    function assertLe(uint a, uint b, string memory err) internal {
        if (a > b) {
            emit log_named_string("Error", err);
            assertLe(a, b);
        }
    }
    function assertLe(int a, int b) internal {
        if (a > b) {
            emit log("Error: a <= b not satisfied [int]");
            emit log_named_int("  Value a", a);
            emit log_named_int("  Value b", b);
            fail();
        }
    }
    function assertLe(int a, int b, string memory err) internal {
        if (a > b) {
            emit log_named_string("Error", err);
            assertLe(a, b);
        }
    }
    function assertLeDecimal(int a, int b, uint decimals) internal {
        if (a > b) {
            emit log("Error: a <= b not satisfied [decimal int]");
            emit log_named_decimal_int("  Value a", a, decimals);
            emit log_named_decimal_int("  Value b", b, decimals);
            fail();
        }
    }
    function assertLeDecimal(int a, int b, uint decimals, string memory err) internal {
        if (a > b) {
            emit log_named_string("Error", err);
            assertLeDecimal(a, b, decimals);
        }
    }
    function assertLeDecimal(uint a, uint b, uint decimals) internal {
        if (a > b) {
            emit log("Error: a <= b not satisfied [decimal uint]");
            emit log_named_decimal_uint("  Value a", a, decimals);
            emit log_named_decimal_uint("  Value b", b, decimals);
            fail();
        }
    }
    function assertLeDecimal(uint a, uint b, uint decimals, string memory err) internal {
        if (a > b) {
            emit log_named_string("Error", err);
            assertGeDecimal(a, b, decimals);
        }
    }

    function assertEq(string memory a, string memory b) internal {
        if (keccak256(abi.encodePacked(a)) != keccak256(abi.encodePacked(b))) {
            emit log("Error: a == b not satisfied [string]");
            emit log_named_string("  Expected", b);
            emit log_named_string("    Actual", a);
            fail();
        }
    }
    function assertEq(string memory a, string memory b, string memory err) internal {
        if (keccak256(abi.encodePacked(a)) != keccak256(abi.encodePacked(b))) {
            emit log_named_string("Error", err);
            assertEq(a, b);
        }
    }

    function checkEq0(bytes memory a, bytes memory b) internal pure returns (bool ok) {
        ok = true;
        if (a.length == b.length) {
            for (uint i = 0; i < a.length; i++) {
                if (a[i] != b[i]) {
                    ok = false;
                }
            }
        } else {
            ok = false;
        }
    }
    function assertEq0(bytes memory a, bytes memory b) internal {
        if (!checkEq0(a, b)) {
            emit log("Error: a == b not satisfied [bytes]");
            emit log_named_bytes("  Expected", b);
            emit log_named_bytes("    Actual", a);
            fail();
        }
    }
    function assertEq0(bytes memory a, bytes memory b, string memory err) internal {
        if (!checkEq0(a, b)) {
            emit log_named_string("Error", err);
            assertEq0(a, b);
        }
    }
}

File 31 of 34 : console.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;

library console {
    address constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    function log(uint p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint)", p0));
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

}

File 32 of 34 : console2.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;

// The orignal console.sol uses `int` and `uint` for computing function selectors, but it should
// use `int256` and `uint256`. This modified version fixes that. This version is recommended
// over `console.sol` if you don't need compatibility with Hardhat as the logs will show up in
// forge stack traces. If you do need compatibility with Hardhat, you must use `console.sol`.
// Reference: https://github.com/NomicFoundation/hardhat/issues/2178

library console2 {
    address constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

}

File 33 of 34 : StdJson.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.9.0;
pragma experimental ABIEncoderV2;

import "./Vm.sol";

// Helpers for parsing keys into types.
library stdJson {

    Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code")))));

    function parseRaw(string memory json, string memory key)
        internal
        returns (bytes memory)
    {
        return vm.parseJson(json, key);
    }

    function readUint(string memory json, string memory key)
        internal
        returns (uint256)
    {
        return abi.decode(vm.parseJson(json, key), (uint256));
    }

    function readUintArray(string memory json, string memory key)
        internal
        returns (uint256[] memory)
    {
        return abi.decode(vm.parseJson(json, key), (uint256[]));
    }

    function readInt(string memory json, string memory key)
        internal
        returns (int256)
    {
        return abi.decode(vm.parseJson(json, key), (int256));
    }

    function readIntArray(string memory json, string memory key)
        internal
        returns (int256[] memory)
    {
        return abi.decode(vm.parseJson(json, key), (int256[]));
    }

    function readBytes32(string memory json, string memory key)
        internal
        returns (bytes32)
    {
        return abi.decode(vm.parseJson(json, key), (bytes32));
    }

    function readBytes32Array(string memory json, string memory key)
        internal
        returns (bytes32[] memory)
    {
        return abi.decode(vm.parseJson(json, key), (bytes32[]));
    }

    function readString(string memory json, string memory key)
        internal
        returns (string memory)
    {
        return abi.decode(vm.parseJson(json, key), (string));
    }

    function readStringArray(string memory json, string memory key)
        internal
        returns (string[] memory)
    {
        return abi.decode(vm.parseJson(json, key), (string[]));
    }

    function readAddress(string memory json, string memory key)
        internal
        returns (address)
    {
        return abi.decode(vm.parseJson(json, key), (address));
    }

    function readAddressArray(string memory json, string memory key)
        internal
        returns (address[] memory)
    {
        return abi.decode(vm.parseJson(json, key), (address[]));
    }

    function readBool(string memory json, string memory key)
        internal
        returns (bool)
    {
        return abi.decode(vm.parseJson(json, key), (bool));
    }

    function readBoolArray(string memory json, string memory key)
        internal
        returns (bool[] memory)
    {
        return abi.decode(vm.parseJson(json, key), (bool[]));
    }

    function readBytes(string memory json, string memory key)
        internal
        returns (bytes memory)
    {
        return abi.decode(vm.parseJson(json, key), (bytes));
    }

    function readBytesArray(string memory json, string memory key)
        internal
        returns (bytes[] memory)
    {
        return abi.decode(vm.parseJson(json, key), (bytes[]));
    }


}

File 34 of 34 : Vm.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.9.0;
pragma experimental ABIEncoderV2;

interface Vm {
    struct Log {
        bytes32[] topics;
        bytes data;
    }

    // Sets block.timestamp (newTimestamp)
    function warp(uint256) external;
    // Sets block.height (newHeight)
    function roll(uint256) external;
    // Sets block.basefee (newBasefee)
    function fee(uint256) external;
    // Sets block.difficulty (newDifficulty)
    function difficulty(uint256) external;
    // Sets block.chainid
    function chainId(uint256) external;
    // Loads a storage slot from an address (who, slot)
    function load(address,bytes32) external returns (bytes32);
    // Stores a value to an address' storage slot, (who, slot, value)
    function store(address,bytes32,bytes32) external;
    // Signs data, (privateKey, digest) => (v, r, s)
    function sign(uint256,bytes32) external returns (uint8,bytes32,bytes32);
    // Gets the address for a given private key, (privateKey) => (address)
    function addr(uint256) external returns (address);
    // Gets the nonce of an account
    function getNonce(address) external returns (uint64);
    // Sets the nonce of an account; must be higher than the current nonce of the account
    function setNonce(address, uint64) external;
    // Performs a foreign function call via the terminal, (stringInputs) => (result)
    function ffi(string[] calldata) external returns (bytes memory);
    // Sets environment variables, (name, value)
    function setEnv(string calldata, string calldata) external;
    // Reads environment variables, (name) => (value)
    function envBool(string calldata) external returns (bool);
    function envUint(string calldata) external returns (uint256);
    function envInt(string calldata) external returns (int256);
    function envAddress(string calldata) external returns (address);
    function envBytes32(string calldata) external returns (bytes32);
    function envString(string calldata) external returns (string memory);
    function envBytes(string calldata) external returns (bytes memory);
    // Reads environment variables as arrays, (name, delim) => (value[])
    function envBool(string calldata, string calldata) external returns (bool[] memory);
    function envUint(string calldata, string calldata) external returns (uint256[] memory);
    function envInt(string calldata, string calldata) external returns (int256[] memory);
    function envAddress(string calldata, string calldata) external returns (address[] memory);
    function envBytes32(string calldata, string calldata) external returns (bytes32[] memory);
    function envString(string calldata, string calldata) external returns (string[] memory);
    function envBytes(string calldata, string calldata) external returns (bytes[] memory);
    // Sets the *next* call's msg.sender to be the input address
    function prank(address) external;
    // Sets all subsequent calls' msg.sender to be the input address until `stopPrank` is called
    function startPrank(address) external;
    // Sets the *next* call's msg.sender to be the input address, and the tx.origin to be the second input
    function prank(address,address) external;
    // Sets all subsequent calls' msg.sender to be the input address until `stopPrank` is called, and the tx.origin to be the second input
    function startPrank(address,address) external;
    // Resets subsequent calls' msg.sender to be `address(this)`
    function stopPrank() external;
    // Sets an address' balance, (who, newBalance)
    function deal(address, uint256) external;
    // Sets an address' code, (who, newCode)
    function etch(address, bytes calldata) external;
    // Expects an error on next call
    function expectRevert(bytes calldata) external;
    function expectRevert(bytes4) external;
    function expectRevert() external;
    // Records all storage reads and writes
    function record() external;
    // Gets all accessed reads and write slot from a recording session, for a given address
    function accesses(address) external returns (bytes32[] memory reads, bytes32[] memory writes);
    // Prepare an expected log with (bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData).
    // Call this function, then emit an event, then call a function. Internally after the call, we check if
    // logs were emitted in the expected order with the expected topics and data (as specified by the booleans)
    function expectEmit(bool,bool,bool,bool) external;
    function expectEmit(bool,bool,bool,bool,address) external;
    // Mocks a call to an address, returning specified data.
    // Calldata can either be strict or a partial match, e.g. if you only
    // pass a Solidity selector to the expected calldata, then the entire Solidity
    // function will be mocked.
    function mockCall(address,bytes calldata,bytes calldata) external;
    // Mocks a call to an address with a specific msg.value, returning specified data.
    // Calldata match takes precedence over msg.value in case of ambiguity.
    function mockCall(address,uint256,bytes calldata,bytes calldata) external;
    // Clears all mocked calls
    function clearMockedCalls() external;
    // Expects a call to an address with the specified calldata.
    // Calldata can either be a strict or a partial match
    function expectCall(address,bytes calldata) external;
    // Expects a call to an address with the specified msg.value and calldata
    function expectCall(address,uint256,bytes calldata) external;
    // Gets the code from an artifact file. Takes in the relative path to the json file
    function getCode(string calldata) external returns (bytes memory);
    // Labels an address in call traces
    function label(address, string calldata) external;
    // If the condition is false, discard this run's fuzz inputs and generate new ones
    function assume(bool) external;
    // Sets block.coinbase (who)
    function coinbase(address) external;
    // Using the address that calls the test contract, has the next call (at this call depth only) create a transaction that can later be signed and sent onchain
    function broadcast() external;
    // Has the next call (at this call depth only) create a transaction with the address provided as the sender that can later be signed and sent onchain
    function broadcast(address) external;
    // Using the address that calls the test contract, has all subsequent calls (at this call depth only) create transactions that can later be signed and sent onchain
    function startBroadcast() external;
    // Has all subsequent calls (at this call depth only) create transactions that can later be signed and sent onchain
    function startBroadcast(address) external;
    // Stops collecting onchain transactions
    function stopBroadcast() external;

    // Reads the entire content of file to string, (path) => (data)
    function readFile(string calldata) external returns (string memory);
    // Get the path of the current project root
    function projectRoot() external returns (string memory);
    // Reads next line of file to string, (path) => (line)
    function readLine(string calldata) external returns (string memory);
    // Writes data to file, creating a file if it does not exist, and entirely replacing its contents if it does.
    // (path, data) => ()
    function writeFile(string calldata, string calldata) external;
    // Writes line to file, creating a file if it does not exist.
    // (path, data) => ()
    function writeLine(string calldata, string calldata) external;
    // Closes file for reading, resetting the offset and allowing to read it from beginning with readLine.
    // (path) => ()
    function closeFile(string calldata) external;
    // Removes file. This cheatcode will revert in the following situations, but is not limited to just these cases:
    // - Path points to a directory.
    // - The file doesn't exist.
    // - The user lacks permissions to remove the file.
    // (path) => ()
    function removeFile(string calldata) external;

    // Convert values to a string, (value) => (stringified value)
    function toString(address) external returns(string memory);
    function toString(bytes calldata) external returns(string memory);
    function toString(bytes32) external returns(string memory);
    function toString(bool) external returns(string memory);
    function toString(uint256) external returns(string memory);
    function toString(int256) external returns(string memory);

    // Convert values from a string, (string) => (parsed value)
    function parseBytes(string calldata) external returns (bytes memory);
    function parseAddress(string calldata) external returns (address);
    function parseUint(string calldata) external returns (uint256);
    function parseInt(string calldata) external returns (int256);
    function parseBytes32(string calldata) external returns (bytes32);
    function parseBool(string calldata) external returns (bool);

    // Record all the transaction logs
    function recordLogs() external;
    // Gets all the recorded logs, () => (logs)
    function getRecordedLogs() external returns (Log[] memory);
    // Snapshot the current state of the evm.
    // Returns the id of the snapshot that was created.
    // To revert a snapshot use `revertTo`
    function snapshot() external returns(uint256);
    // Revert the state of the evm to a previous snapshot
    // Takes the snapshot id to revert to.
    // This deletes the snapshot and all snapshots taken after the given snapshot id.
    function revertTo(uint256) external returns(bool);

    // Creates a new fork with the given endpoint and block and returns the identifier of the fork
    function createFork(string calldata,uint256) external returns(uint256);
    // Creates a new fork with the given endpoint and the _latest_ block and returns the identifier of the fork
    function createFork(string calldata) external returns(uint256);
    // Creates _and_ also selects a new fork with the given endpoint and block and returns the identifier of the fork
    function createSelectFork(string calldata,uint256) external returns(uint256);
    // Creates _and_ also selects a new fork with the given endpoint and the latest block and returns the identifier of the fork
    function createSelectFork(string calldata) external returns(uint256);
    // Takes a fork identifier created by `createFork` and sets the corresponding forked state as active.
    function selectFork(uint256) external;
    /// Returns the currently active fork
    /// Reverts if no fork is currently active
    function activeFork() external returns(uint256);
    // Updates the currently active fork to given block number
    // This is similar to `roll` but for the currently active fork
    function rollFork(uint256) external;
    // Updates the given fork to given block number
    function rollFork(uint256 forkId, uint256 blockNumber) external;

    // Marks that the account(s) should use persistent storage across fork swaps in a multifork setup
    // Meaning, changes made to the state of this account will be kept when switching forks
    function makePersistent(address) external;
    function makePersistent(address, address) external;
    function makePersistent(address, address, address) external;
    function makePersistent(address[] calldata) external;
    // Revokes persistent status from the address, previously added via `makePersistent`
    function revokePersistent(address) external;
    function revokePersistent(address[] calldata) external;
    // Returns true if the account is marked as persistent
    function isPersistent(address) external returns (bool);

    // Returns the RPC url for the given alias
    function rpcUrl(string calldata) external returns(string memory);
    // Returns all rpc urls and their aliases `[alias, url][]`
    function rpcUrls() external returns(string[2][] memory);

    // Derive a private key from a provided mnenomic string (or mnenomic file path) at the derivation path m/44'/60'/0'/0/{index}
    function deriveKey(string calldata, uint32) external returns (uint256);
    // Derive a private key from a provided mnenomic string (or mnenomic file path) at the derivation path {path}{index}
    function deriveKey(string calldata, string calldata, uint32) external returns (uint256);
    // parseJson

    // Given a string of JSON, return the ABI-encoded value of provided key
    // (stringified json, key) => (ABI-encoded data)
    // Read the note below!
    function parseJson(string calldata, string calldata) external returns(bytes memory);

    // Given a string of JSON, return it as ABI-encoded, (stringified json, key) => (ABI-encoded data)
    // Read the note below!
    function parseJson(string calldata) external returns(bytes memory);

    // Note:
    // ----
    // In case the returned value is a JSON object, it's encoded as a ABI-encoded tuple. As JSON objects
    // don't have the notion of ordered, but tuples do, they JSON object is encoded with it's fields ordered in
    // ALPHABETICAL ordser. That means that in order to succesfully decode the tuple, we need to define a tuple that
    // encodes the fields in the same order, which is alphabetical. In the case of Solidity structs, they are encoded
    // as tuples, with the attributes in the order in which they are defined.
    // For example: json = { 'a': 1, 'b': 0xa4tb......3xs}
    // a: uint256
    // b: address
    // To decode that json, we need to define a struct or a tuple as follows:
    // struct json = { uint256 a; address b; }
    // If we defined a json struct with the opposite order, meaning placing the address b first, it would try to
    // decode the tuple in that order, and thus fail.

}

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

Contract ABI

[{"inputs":[{"internalType":"address","name":"_reader","type":"address"},{"internalType":"address","name":"_stfxImplementation","type":"address"},{"internalType":"uint256","name":"_capacityPerStf","type":"uint256"},{"internalType":"uint256","name":"_minInvestmentAmount","type":"uint256"},{"internalType":"uint256","name":"_maxInvestmentAmount","type":"uint256"},{"internalType":"uint256","name":"_maxLeverage","type":"uint256"},{"internalType":"address","name":"_usdc","type":"address"},{"internalType":"address","name":"_weth","type":"address"},{"internalType":"address","name":"_admin","type":"address"},{"internalType":"address","name":"_treasury","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"max","type":"uint256"},{"internalType":"uint256","name":"given","type":"uint256"}],"name":"AboveMax","type":"error"},{"inputs":[],"name":"AlreadyOpened","type":"error"},{"inputs":[{"internalType":"uint256","name":"min","type":"uint256"},{"internalType":"uint256","name":"given","type":"uint256"}],"name":"BelowMin","type":"error"},{"inputs":[],"name":"CantClose","type":"error"},{"inputs":[],"name":"CantOpen","type":"error"},{"inputs":[{"internalType":"address","name":"fund","type":"address"}],"name":"FundExists","type":"error"},{"inputs":[{"internalType":"uint256","name":"desired","type":"uint256"},{"internalType":"uint256","name":"given","type":"uint256"}],"name":"InvalidChainId","type":"error"},{"inputs":[{"internalType":"address","name":"desired","type":"address"},{"internalType":"address","name":"given","type":"address"}],"name":"NoAccess","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"NoBaseToken","type":"error"},{"inputs":[],"name":"NoCloseActions","type":"error"},{"inputs":[],"name":"NoOpenPositions","type":"error"},{"inputs":[{"internalType":"uint256","name":"entry","type":"uint256"},{"internalType":"uint256","name":"exit","type":"uint256"},{"internalType":"bool","name":"direction","type":"bool"}],"name":"NotEligible","type":"error"},{"inputs":[],"name":"NotFinalised","type":"error"},{"inputs":[],"name":"NotOpened","type":"error"},{"inputs":[],"name":"OpenPosition","type":"error"},{"inputs":[{"internalType":"uint256","name":"desired","type":"uint256"},{"internalType":"uint256","name":"given","type":"uint256"}],"name":"StillFundraising","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroAmount","type":"error"},{"inputs":[],"name":"ZeroTokenBalance","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"admin","type":"address"}],"name":"AdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"capacity","type":"uint256"}],"name":"CapacityPerStfChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"investor","type":"address"},{"indexed":true,"internalType":"address","name":"stfxAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Claimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_stfxAddress","type":"address"},{"indexed":false,"internalType":"bool","name":"_isOpen","type":"bool"},{"indexed":false,"internalType":"uint256","name":"_triggerPrice","type":"uint256"}],"name":"CreatedPositionAgain","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_stfxAddress","type":"address"},{"indexed":true,"internalType":"address","name":"investor","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"DepositIntoFund","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_stfxAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"_remainingBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_managerFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_protocolFee","type":"uint256"}],"name":"FeesTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stfxAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"fundDeadline","type":"uint256"}],"name":"FundDeadlineChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_stfxAddress","type":"address"},{"indexed":false,"internalType":"bool","name":"_isLimit","type":"bool"},{"indexed":false,"internalType":"uint256","name":"triggerPrice","type":"uint256"}],"name":"FundraisingCloseAndVaultOpened","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_stfxAddress","type":"address"}],"name":"FundraisingClosed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_reader","type":"address"},{"indexed":false,"internalType":"address","name":"_stfxImplementation","type":"address"},{"indexed":false,"internalType":"uint256","name":"_capacityPerStf","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_minInvestmentAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_maxInvestmentAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_maxLeverage","type":"uint256"},{"indexed":false,"internalType":"address","name":"_usdc","type":"address"},{"indexed":false,"internalType":"address","name":"_weth","type":"address"},{"indexed":false,"internalType":"address","name":"_admin","type":"address"},{"indexed":false,"internalType":"address","name":"_treasury","type":"address"}],"name":"InitializedVault","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"managerFee","type":"uint256"}],"name":"ManagerFeeChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"manager","type":"address"},{"indexed":false,"internalType":"bool","name":"isManaging","type":"bool"}],"name":"ManagingFundUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxDeadlineForPosition","type":"uint256"}],"name":"MaxDeadlineForPositionChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxFundraisingPeriod","type":"uint256"}],"name":"MaxFundraisingPeriodChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxAmount","type":"uint256"}],"name":"MaxInvestmentAmountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxLeverage","type":"uint256"}],"name":"MaxLeverageChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxAmount","type":"uint256"}],"name":"MinInvestmentAmountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"minLeverage","type":"uint256"}],"name":"MinLeverageChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"baseToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"fundraisingPeriod","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"entryPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"targetPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"liquidationPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"leverage","type":"uint256"},{"indexed":false,"internalType":"bool","name":"tradeDirection","type":"bool"},{"indexed":true,"internalType":"address","name":"stfxAddress","type":"address"},{"indexed":true,"internalType":"address","name":"manager","type":"address"}],"name":"NewFundCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stfxAddress","type":"address"}],"name":"NoFillVaultClosed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_stfxAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"_orderIndex","type":"uint256"},{"indexed":false,"internalType":"bool","name":"_isOpen","type":"bool"},{"indexed":false,"internalType":"uint256","name":"_totalRaised","type":"uint256"}],"name":"OrderCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_stfxAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"_size","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_triggerPrice","type":"uint256"},{"indexed":false,"internalType":"bool","name":"_isOpen","type":"bool"},{"indexed":false,"internalType":"bool","name":"_triggerAboveThreshold","type":"bool"}],"name":"OrderUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"protocolFee","type":"uint256"}],"name":"ProtocolFeeChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"reader","type":"address"}],"name":"ReaderAddressChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"referralCode","type":"bytes32"}],"name":"ReferralCodeChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stfxAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"remainingBalance","type":"uint256"}],"name":"StfRemainingBalanceUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stfxAddress","type":"address"},{"indexed":false,"internalType":"enum IStfxStorage.StfStatus","name":"status","type":"uint8"}],"name":"StfStatusUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stfxAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"totalRaised","type":"uint256"}],"name":"StfTotalRaisedUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stfx","type":"address"}],"name":"StfxImplementationChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"treasury","type":"address"}],"name":"TreasuryChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"usdc","type":"address"}],"name":"UsdcAddressChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_stfAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"size","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isLimit","type":"bool"},{"indexed":false,"internalType":"uint256","name":"triggerPrice","type":"uint256"},{"indexed":false,"internalType":"bool","name":"closedCompletely","type":"bool"}],"name":"VaultClosed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stfxAddress","type":"address"}],"name":"VaultLiquidated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_stfAddress","type":"address"},{"indexed":false,"internalType":"bool","name":"isLimit","type":"bool"},{"indexed":false,"internalType":"uint256","name":"triggerPrice","type":"uint256"}],"name":"VaultOpened","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"weth","type":"address"}],"name":"WethAddressChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"WithdrawEth","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stfxAddress","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"bool","name":"isEth","type":"bool"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"WithdrawFromStf","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"WithdrawToken","type":"event"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"actualTotalRaised","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_stfxAddress","type":"address"},{"internalType":"uint256","name":"_orderIndex","type":"uint256"},{"internalType":"bool","name":"_isOpen","type":"bool"}],"name":"cancelOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_stfxAddress","type":"address"},{"internalType":"uint256","name":"_orderIndex","type":"uint256"}],"name":"cancelStfAfterOpening","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_stfxAddress","type":"address"},{"internalType":"bool","name":"hasCloseOrder","type":"bool"},{"internalType":"uint256","name":"_orderIndex","type":"uint256"},{"internalType":"uint256","name":"_triggerPrice","type":"uint256"},{"internalType":"bool","name":"_triggerAboveThreshold","type":"bool"}],"name":"cancelStfAfterPositionDeadline","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_stfxAddress","type":"address"}],"name":"cancelStfByManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_stfxAddress","type":"address"}],"name":"cancelVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"capacityPerStf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_stfxAddress","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_stfxAddress","type":"address"},{"internalType":"address","name":"_investor","type":"address"}],"name":"claimableAmount","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_stfxAddress","type":"address"}],"name":"closeFundraising","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_stfxAddress","type":"address"},{"internalType":"bool","name":"_isLimit","type":"bool"},{"internalType":"uint256","name":"_triggerPrice","type":"uint256"}],"name":"closeFundraisingAndOpenPosition","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_stfxAddress","type":"address"}],"name":"closeLiquidatedVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_stfxAddress","type":"address"},{"internalType":"bool","name":"_isLimit","type":"bool"},{"internalType":"uint256","name":"_size","type":"uint256"},{"internalType":"uint256","name":"_triggerPrice","type":"uint256"},{"internalType":"bool","name":"_triggerAboveThreshold","type":"bool"}],"name":"closePosition","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"baseToken","type":"address"},{"internalType":"bool","name":"tradeDirection","type":"bool"},{"internalType":"uint256","name":"fundraisingPeriod","type":"uint256"},{"internalType":"uint256","name":"entryPrice","type":"uint256"},{"internalType":"uint256","name":"targetPrice","type":"uint256"},{"internalType":"uint256","name":"liquidationPrice","type":"uint256"},{"internalType":"uint256","name":"leverage","type":"uint256"}],"internalType":"struct IStfxStorage.Stf","name":"_stf","type":"tuple"}],"name":"createNewStf","outputs":[{"internalType":"address","name":"stfxAddress","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_stfxAddress","type":"address"},{"internalType":"bool","name":"_isLimit","type":"bool"},{"internalType":"bool","name":"_isOpen","type":"bool"},{"internalType":"uint256","name":"_size","type":"uint256"},{"internalType":"uint256","name":"_triggerPrice","type":"uint256"},{"internalType":"bool","name":"_triggerAboveThreshold","type":"bool"}],"name":"createPositionAgain","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_stfxAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"depositIntoFund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_stfxAddress","type":"address"}],"name":"distributeProfits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_stfxAddress","type":"address"},{"internalType":"address","name":"_investor","type":"address"}],"name":"getClaimAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_stfxAddress","type":"address"},{"internalType":"address","name":"_investor","type":"address"}],"name":"getClaimed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_stfxAddress","type":"address"}],"name":"getPnl","outputs":[{"internalType":"uint256","name":"mFee","type":"uint256"},{"internalType":"uint256","name":"pFee","type":"uint256"},{"internalType":"int256","name":"pnlBeforeFees","type":"int256"},{"internalType":"int256","name":"pnlAfterFees","type":"int256"},{"internalType":"bool","name":"isDistributed","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_stfxAddress","type":"address"}],"name":"getPosition","outputs":[{"internalType":"uint256","name":"size","type":"uint256"},{"internalType":"uint256","name":"collateral","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"entryFundingRate","type":"uint256"},{"internalType":"uint256","name":"reserveAmount","type":"uint256"},{"internalType":"uint256","name":"realisedPnl","type":"uint256"},{"internalType":"bool","name":"isProfit","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_stfxAddress","type":"address"}],"name":"getStatusOfStf","outputs":[{"internalType":"enum IStfxStorage.StfStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_stfxAddress","type":"address"}],"name":"getStfInfo","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"enum IStfxStorage.StfStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_stfxAddress","type":"address"},{"internalType":"address","name":"_investor","type":"address"}],"name":"getUserAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_stfxAddress","type":"address"}],"name":"isCancelled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_stfxAddress","type":"address"}],"name":"isClosed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_stfxAddress","type":"address"}],"name":"isDistributed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_stfxAddress","type":"address"}],"name":"isLiquidated","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isManagingFund","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_stfxAddress","type":"address"}],"name":"isNotOpened","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_stfxAddress","type":"address"}],"name":"isOpened","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"managerFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"managerFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxDeadlineForPosition","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxFundraisingPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxInvestmentAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxLeverage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minInvestmentAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minLeverage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_stfxAddress","type":"address"},{"internalType":"bool","name":"_isLimit","type":"bool"},{"internalType":"uint256","name":"_triggerPrice","type":"uint256"}],"name":"openPosition","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"protocolFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"reader","outputs":[{"internalType":"contract IReader","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"referralCode","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_admin","type":"address"}],"name":"setAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_capacity","type":"uint256"}],"name":"setCapacityPerStf","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_stfxAddress","type":"address"},{"internalType":"uint256","name":"newFundDeadline","type":"uint256"}],"name":"setFundDeadline","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_manager","type":"address"},{"internalType":"bool","name":"_isManaging","type":"bool"}],"name":"setIsManagingFund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newManagerFee","type":"uint256"}],"name":"setManagerFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxDeadlineForPosition","type":"uint256"}],"name":"setMaxDeadlineForPosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxFundraisingPeriod","type":"uint256"}],"name":"setMaxFundraisingPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"setMaxInvestmentAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxLeverage","type":"uint256"}],"name":"setMaxLeverage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"setMinInvestmentAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minLeverage","type":"uint256"}],"name":"setMinLeverage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newProtocolFee","type":"uint256"}],"name":"setProtocolFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_reader","type":"address"}],"name":"setReader","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_referralCode","type":"bytes32"}],"name":"setReferralCode","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_remainingBalance","type":"uint256"}],"name":"setStfRemainingBalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum IStfxStorage.StfStatus","name":"_status","type":"uint8"}],"name":"setStfStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_totalRaised","type":"uint256"}],"name":"setStfTotalRaised","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"stfx","type":"address"}],"name":"setStfxImplementation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_treasury","type":"address"}],"name":"setTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_usdc","type":"address"}],"name":"setUsdc","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_weth","type":"address"}],"name":"setWeth","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_stfxAddress","type":"address"}],"name":"shouldCancelOpenLimitOrder","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_stfxAddress","type":"address"}],"name":"shouldDistribute","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"stfInfo","outputs":[{"internalType":"address","name":"stfxAddress","type":"address"},{"internalType":"address","name":"manager","type":"address"},{"internalType":"uint256","name":"totalRaised","type":"uint256"},{"internalType":"uint256","name":"remainingAmountAfterClose","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"fundDeadline","type":"uint256"},{"internalType":"enum IStfxStorage.StfStatus","name":"status","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stfxImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawEth","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_stfxAddress","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"bool","name":"isEth","type":"bool"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawFromStf","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawToken","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60806040523480156200001157600080fd5b506040516200632e3803806200632e833981016040819052620000349162000296565b6000805460ff191690556001600160a01b038a16620000665760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b0389166200008e5760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b038416620000b65760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b038316620000de5760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b038216620001065760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b0381166200012e5760405163d92e233d60e01b815260040160405180910390fd5b600680546001600160a01b038c81166001600160a01b0319928316811790935560028054831633179055600580548d8316908416811790915560078c905560088b905560098a9055620f4240600d55600c89905560008054898416610100818102610100600160a81b031990931692909217909255600180548a8616908716811790915567d02ab486cedc0000600a55674563918244f40000600b5562093a80600e55600380548a8716908816811790915560048054968a1696909716861790965562278d00600f556040805197885260208801949094528684018f9052606087018e9052608087018d905260a087018c905260c087019290925260e0860191909152840192909252610120830152517f5ab487967be9cd45fbc6dd68ac04d82c7dc95a7a28112dcea3df97473ebd21d0918190036101400190a15050505050505050505062000341565b80516001600160a01b03811681146200029157600080fd5b919050565b6000806000806000806000806000806101408b8d031215620002b757600080fd5b620002c28b62000279565b9950620002d260208c0162000279565b985060408b0151975060608b0151965060808b0151955060a08b01519450620002fe60c08c0162000279565b93506200030e60e08c0162000279565b92506200031f6101008c0162000279565b9150620003306101208c0162000279565b90509295989b9194979a5092959850565b615fdd80620003516000396000f3fe6080604052600436106105585760003560e01c80638f725541116102ca578063ccf362c811610179578063e1f8c1be116100d6578063f41bb5bf1161008a578063f7f2b25a1161006f578063f7f2b25a14611015578063f851a44014611035578063faee7a2b1461105557600080fd5b8063f41bb5bf14610fd5578063f6fa527a14610ff557600080fd5b8063ed3b914c116100bb578063ed3b914c14610f82578063f0f4426014610f95578063f217c92914610fb557600080fd5b8063e1f8c1be14610ed1578063ea49ee6f14610f3857600080fd5b8063d7a4056f1161012d578063dadb98ed11610112578063dadb98ed14610e6e578063dcf844a714610e8e578063dfabb02614610ebb57600080fd5b8063d7a4056f14610e38578063d8b6d25214610e5857600080fd5b8063d3127e631161015e578063d3127e6314610dd8578063d4fc42c614610df8578063d736296514610e1857600080fd5b8063ccf362c814610d78578063d0b272a114610dc557600080fd5b8063ac2e625f11610227578063be39cce2116101db578063c374d2d1116101c0578063c374d2d114610d18578063ca3b215314610d38578063cb14687914610d5857600080fd5b8063be39cce214610ccb578063c342da0c14610cf857600080fd5b8063b0e21e8a1161020c578063b0e21e8a14610c75578063b75502b114610c8b578063b8d1452f14610cab57600080fd5b8063ac2e625f14610c4c578063ae3302c214610c5f57600080fd5b80639d2629631161027e578063a0914e6a11610263578063a0914e6a14610bec578063a3b3f60614610c0c578063a548929714610c2c57600080fd5b80639d26296314610bac5780639f19165914610bcc57600080fd5b806391b1cb56116102af57806391b1cb5614610b635780639598da7f14610b765780639c7632fc14610b9657600080fd5b80638f72554114610b2d5780638ff88f1714610b4d57600080fd5b80635c943880116104265780637806615f1161038357806387c2b5b3116103375780638c21cd521161031c5780638c21cd5214610ad75780638c43d73914610af75780638da5cb5b14610b0d57600080fd5b806387c2b5b314610a8a57806389a9a7ee14610ab757600080fd5b80637d109647116103685780637d10964714610a255780637fbb108614610a555780638456cb5914610a7557600080fd5b80637806615f146109e5578063787dce3d14610a0557600080fd5b80636b3d3d2c116103da578063704b6c02116103bf578063704b6c021461092657806374d711f1146109465780637776b1a71461096657600080fd5b80636b3d3d2c146108e65780636ef178bf1461090657600080fd5b80635fe633bc1161040b5780635fe633bc1461086e57806361d027b31461088e5780636943b017146108c657600080fd5b80635c943880146108405780635c975abb1461085657600080fd5b80631e83409a116104d45780633f4ba83a116104885780634cd2745a1161046d5780634cd2745a146107c15780634d298a07146107e1578063541c7480146107f757600080fd5b80633f4ba83a1461078c578063456f44de146107a157600080fd5b8063279847f3116104b9578063279847f3146107295780632d5aa3ad1461073c5780633ebf64741461075c57600080fd5b80631e83409a146106e557806320f6f76f1461070557600080fd5b806313af40351161052b57806316c197391161051057806316c197391461064e5780631b9a91a4146106a55780631d27bdca146106c557600080fd5b806313af4035146105df57806313ea7c89146105ff57600080fd5b806301e336671461055d57806307c5a0ff1461057f578063082dbade1461059f5780630a19a012146105bf575b600080fd5b34801561056957600080fd5b5061057d610578366004615731565b611075565b005b34801561058b57600080fd5b5061057d61059a366004615772565b6112a4565b3480156105ab57600080fd5b5061057d6105ba366004615772565b611363565b3480156105cb57600080fd5b5061057d6105da366004615772565b6113f9565b3480156105eb57600080fd5b5061057d6105fa36600461578b565b6114bf565b34801561060b57600080fd5b5061061f61061a36600461578b565b6115a1565b6040805195865260208601949094529284019190915260608301521515608082015260a0015b60405180910390f35b34801561065a57600080fd5b5061066e61066936600461578b565b611675565b604080519788526020880196909652948601939093526060850191909152608084015260a0830152151560c082015260e001610645565b3480156106b157600080fd5b5061057d6106c03660046157af565b611897565b3480156106d157600080fd5b5061057d6106e03660046157af565b6119db565b3480156106f157600080fd5b5061057d61070036600461578b565b611cd9565b34801561071157600080fd5b5061071b600d5481565b604051908152602001610645565b61057d6107373660046157e9565b611eb6565b34801561074857600080fd5b5061057d610757366004615772565b6121c8565b34801561076857600080fd5b5061077c61077736600461578b565b61223d565b6040519015158152602001610645565b34801561079857600080fd5b5061057d612285565b3480156107ad57600080fd5b5061057d6107bc366004615848565b6122d7565b3480156107cd57600080fd5b5061057d6107dc36600461578b565b61238b565b3480156107ed57600080fd5b5061071b60085481565b34801561080357600080fd5b5061083361081236600461578b565b6001600160a01b031660009081526011602052604090206006015460ff1690565b60405161064591906158d3565b34801561084c57600080fd5b5061071b600e5481565b34801561086257600080fd5b5060005460ff1661077c565b34801561087a57600080fd5b5061057d61088936600461578b565b612502565b34801561089a57600080fd5b506004546108ae906001600160a01b031681565b6040516001600160a01b039091168152602001610645565b3480156108d257600080fd5b5061077c6108e136600461578b565b6125a4565b3480156108f257600080fd5b506108ae6109013660046158e1565b6125c3565b34801561091257600080fd5b5061071b6109213660046158f3565b612b5f565b34801561093257600080fd5b5061057d61094136600461578b565b612cfe565b34801561095257600080fd5b5061057d61096136600461578b565b612de0565b34801561097257600080fd5b506109d261098136600461578b565b6001600160a01b039081166000908152601160205260409020805460018201546002830154600384015460048501546005860154600690960154948716979390961695919490939192909160ff1690565b604051610645979695949392919061592c565b3480156109f157600080fd5b506005546108ae906001600160a01b031681565b348015610a1157600080fd5b5061057d610a20366004615772565b612ef8565b348015610a3157600080fd5b5061077c610a4036600461578b565b60126020526000908152604090205460ff1681565b348015610a6157600080fd5b5061057d610a70366004615772565b612f75565b348015610a8157600080fd5b5061057d61302d565b348015610a9657600080fd5b5061071b610aa536600461578b565b60146020526000908152604090205481565b348015610ac357600080fd5b5061057d610ad2366004615979565b61307d565b348015610ae357600080fd5b5061077c610af236600461578b565b613115565b348015610b0357600080fd5b5061071b60075481565b348015610b1957600080fd5b506002546108ae906001600160a01b031681565b348015610b3957600080fd5b5061057d610b48366004615772565b613186565b348015610b5957600080fd5b5061071b600f5481565b61057d610b713660046157e9565b61324c565b348015610b8257600080fd5b5061057d610b9136600461578b565b61352d565b348015610ba257600080fd5b5061071b600a5481565b348015610bb857600080fd5b5061077c610bc736600461578b565b6135cf565b348015610bd857600080fd5b5061071b610be73660046158f3565b613653565b348015610bf857600080fd5b5061057d610c07366004615772565b613684565b348015610c1857600080fd5b5061077c610c2736600461578b565b613712565b348015610c3857600080fd5b5061057d610c47366004615772565b613731565b61057d610c5a3660046159a7565b6137fb565b348015610c6b57600080fd5b5061071b600c5481565b348015610c8157600080fd5b5061071b600b5481565b348015610c9757600080fd5b5061057d610ca63660046157af565b613b7c565b348015610cb757600080fd5b5061057d610cc636600461578b565b613da2565b348015610cd757600080fd5b5061071b610ce636600461578b565b60136020526000908152604090205481565b348015610d0457600080fd5b5061077c610d1336600461578b565b613e84565b348015610d2457600080fd5b5061077c610d3336600461578b565b613ea3565b348015610d4457600080fd5b5061057d610d53366004615a17565b613ec1565b348015610d6457600080fd5b5061057d610d7336600461578b565b614119565b348015610d8457600080fd5b5061077c610d933660046158f3565b6001600160a01b0391821660009081526011602090815260408083209390941682526009909201909152205460ff1690565b61057d610dd3366004615a7b565b614200565b348015610de457600080fd5b5061057d610df3366004615772565b61456c565b348015610e0457600080fd5b506006546108ae906001600160a01b031681565b348015610e2457600080fd5b5061057d610e333660046157af565b614631565b348015610e4457600080fd5b5061057d610e5336600461578b565b61472c565b348015610e6457600080fd5b5061071b60105481565b348015610e7a57600080fd5b5061077c610e8936600461578b565b6148a5565b348015610e9a57600080fd5b5061071b610ea936600461578b565b60156020526000908152604090205481565b348015610ec757600080fd5b5061071b60095481565b348015610edd57600080fd5b506109d2610eec36600461578b565b60116020526000908152604090208054600182015460028301546003840154600485015460058601546006909601546001600160a01b0395861696959094169492939192909160ff1687565b348015610f4457600080fd5b5061071b610f533660046158f3565b6001600160a01b0391821660009081526011602090815260408083209390941682526008909201909152205490565b61057d610f90366004615a7b565b6148c4565b348015610fa157600080fd5b5061057d610fb036600461578b565b614c25565b348015610fc157600080fd5b5061057d610fd0366004615772565b614d07565b348015610fe157600080fd5b5061057d610ff0366004615772565b614d84565b34801561100157600080fd5b5061057d61101036600461578b565b614e48565b34801561102157600080fd5b5061057d61103036600461578b565b614fb3565b34801561104157600080fd5b506003546108ae906001600160a01b031681565b34801561106157600080fd5b5061057d611070366004615aab565b6151d9565b6002546001600160a01b031633146110ba57600254604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044015b60405180910390fd5b6001600160a01b0382166110fa576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000906001600160a01b038516906370a0823190602401602060405180830381865afa15801561115a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061117e9190615aed565b9050808211156111c4576040517f83f227e900000000000000000000000000000000000000000000000000000000815260048101829052602481018390526044016110b1565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000081526001600160a01b0384811660048301526024820184905285169063a9059cbb906044016020604051808303816000875af115801561122c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112509190615b06565b50826001600160a01b0316846001600160a01b03167f037238854fe57fbf51f09946f854fc3916fe83938d6521f09bd05463839f13048460405161129691815260200190565b60405180910390a350505050565b6002546001600160a01b031633146112e457600254604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6112ec6154dc565b6001811015611327576040517f1f2a200500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60078190556040518181527fc968c2b2d4bd824c9eeae67e73329723fd6055c7f5c7880094263ec6e2efe0c6906020015b60405180910390a150565b336000818152601160205260409020805490916001600160a01b03909116146113b8576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6003810182905560405182815233907fec9e3aa9b0e25af4ea15e340b3c4e013cb69d0529dcb1ddf9a735cc4807c3aae906020015b60405180910390a25050565b6002546001600160a01b0316331461143957600254604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6114416154dc565b6201518081101561148a576040517f52be750b000000000000000000000000000000000000000000000000000000008152620151806004820152602481018290526044016110b1565b600f8190556040518181527f8cf6167c03aff0cae83560b208602b7fb5c79d5d29336d97c23f087d12c163ad90602001611358565b6002546001600160a01b031633146114ff57600254604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6001600160a01b03811661153f576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517fa2ea9883a321a3e97b8266c2b078bfeec6d50c711ed71f874a90d500ae2eaf3690600090a250565b6001600160a01b038116600090815260116020526040812081908190819081906005600682015460ff1660058111156115dc576115dc615869565b036115e657600191505b6001600160a01b03871660009081526014602090815260408083205460158352818420546013909352922054600384015492985090965090869061162b908990615b52565b6116359190615b52565b61163f9190615b6a565b6001600160a01b038816600090815260136020526040902054600383015491955061166991615b6a565b92505091939590929450565b600080600080600080600080886001600160a01b031663e113c9b46040518163ffffffff1660e01b815260040160e060405180830381865afa1580156116bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116e39190615c5c565b90506000600660009054906101000a90046001600160a01b03166001600160a01b031663191622ff6040518163ffffffff1660e01b8152600401600060405180830381865afa15801561173a573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526117809190810190615cf2565b60008151811061179257611792615d98565b60200260200101519050806001600160a01b0316634a3f088d8b84602001516117cb5760005461010090046001600160a01b03166117ce565b84515b8551602087015160405160e086901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b039485166004820152928416602484015292166044820152901515606482015260840161010060405180830381865afa158015611849573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061186d9190615dc7565b50809950819a50829b50839c50849d50859e50869f50505050505050505050919395979092949650565b6002546001600160a01b031633146118d757600254604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6001600160a01b038216611917576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b478082111561195c576040517f83f227e900000000000000000000000000000000000000000000000000000000815260048101829052602481018390526044016110b1565b6040516001600160a01b0384169083156108fc029084906000818181858888f19350505050158015611992573d6000803e3d6000fd5b50826001600160a01b03167fccbd99ba6da8f29b2a4f65e474e3c3973564d356c162c08d45f3dc7f0cb5b3aa836040516119ce91815260200190565b60405180910390a2505050565b6119e36154dc565b6001600160a01b03821660009081526011602052604090206004810154421115611a45576004818101546040517f83f227e9000000000000000000000000000000000000000000000000000000008152918201524260248201526044016110b1565b600854821015611a8f576008546040517f52be750b0000000000000000000000000000000000000000000000000000000081526004810191909152602481018390526044016110b1565b600954336000908152600783016020526040902054611aaf908490615b52565b1115611b1057600954336000908152600783016020526040902054611ad5908490615b52565b6040517f83f227e9000000000000000000000000000000000000000000000000000000008152600481019290925260248201526044016110b1565b6000600682015460ff166005811115611b2b57611b2b615869565b14611b62576040517f1da42b2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600754828260020154611b759190615b52565b1115611b8e57600754828260020154611ad59190615b52565b81816002016000828254611ba29190615b52565b909155505033600090815260078201602052604081208054849290611bc8908490615b52565b90915550506001600160a01b03831660009081526013602052604081208054849290611bf5908490615b52565b90915550506000546040517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018490526101009091046001600160a01b0316906323b872dd906064016020604051808303816000875af1158015611c6e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c929190615b06565b5060405182815233906001600160a01b038516907f6de21c38099746d11a6455c0eacd00c03c175731ddded0ca3f86a70e5ee17b5a906020015b60405180910390a3505050565b611ce16154dc565b6001600160a01b03811660009081526011602052604090206005600682015460ff166005811115611d1457611d14615869565b14158015611d3b57506004600682015460ff166005811115611d3857611d38615869565b14155b15611d72576040517f1ba1720400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611d7e8333612b5f565b90506001811015611dbb576040517f9ab109cb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360008181526009840160209081526040808320805460ff1916600117905560088601909152808220849055905490517fa9059cbb00000000000000000000000000000000000000000000000000000000815260048101929092526024820183905261010090046001600160a01b03169063a9059cbb906044016020604051808303816000875af1158015611e54573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e789190615b06565b506040518181526001600160a01b0384169033907ff7a40077ff7a04c7e61f6f26fb13774259ddf1b6bce9ecf26a8276cdd399268390602001611ccc565b611ebe6154dc565b6001600160a01b038516600090815260116020526040812090611ee087611675565b5050505050509050600f544211611f3057600f546040517f52be750b00000000000000000000000000000000000000000000000000000000815260048101919091524260248201526044016110b1565b6003546001600160a01b03163314611f74576040517ff9202d0b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002600683015460ff166005811115611f8f57611f8f615869565b14158015611fb657506001600683015460ff166005811115611fb357611fb3615869565b14155b15611fed576040517ff9202d0b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001811015612028576040517ff0c0e21000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b85156120bf576040517ff88d204700000000000000000000000000000000000000000000000000000000815260048101869052600060248201819052906001600160a01b0389169063f88d2047906044016020604051808303816000875af1158015612098573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120bc9190615aed565b50505b6040517f9b0f0f0c00000000000000000000000000000000000000000000000000000000815260006004820152602481018290526044810185905283151560648201526001600160a01b03881690639b0f0f0c90349060840160206040518083038185885af1158015612136573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019061215b9190615b06565b5060068201805460ff191660021790556040805182815260006020820152908101859052600160608201526001600160a01b038816907f10fe341e1741d7d3441096e3fac5b3aca87a6900380b8227a428d5753c9d7436906080015b60405180910390a250505050505050565b6002546001600160a01b0316331461220857600254604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b60108190556040518181527f0770d360699a0d8cb23e6911d959e5433052103c9fef4ea9dcca7ea0c05d995390602001611358565b6001600160a01b038116600090815260116020526040812060055b600682015460ff16600581111561227157612271615869565b0361227f5750600192915050565b50919050565b6003546001600160a01b031633146122c557600354604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6122cd615549565b6122d56155b5565b565b336000818152601160205260409020805490916001600160a01b039091161461232c576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60068101805483919060ff1916600183600581111561234d5761234d615869565b0217905550336001600160a01b03167fa35440f710f530b15483dadda015cac6bac4a69bf1a1cdad95d4ae67ae8c0480836040516113ed91906158d3565b6123936154dc565b6001600160a01b038181166000908152601160205260409020600181015490911633146123ea576001810154604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6000600682015460ff16600581111561240557612405615869565b1461243c576040517f4813c5bf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806005015481600401546124509190615b52565b421115612489576040517ff9202d0b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006005820181905560048083019190915560068201805460ff19166001835b021790555060018101546001600160a01b03908116600090815260126020526040808220805460ff1916905551918416917f4a808f5ebb4e18df4b677052792ca735ec5c9788cd7476f3a9cfd6cebfda74459190a25050565b6002546001600160a01b0316331461254257600254604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b600580547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517f9b0f1509d9404d6b879d0b12becc0b301899423cdcc45fa855aa25c89c8b95b790600090a250565b6001600160a01b03811660009081526011602052604081206002612258565b60006125cd6154dc565b3360009081526012602052604090205460ff1615612619576040517f9ba436c40000000000000000000000000000000000000000000000000000000081523360048201526024016110b1565b6103848260400135101561266757604080517f52be750b00000000000000000000000000000000000000000000000000000000815261038460048201529083013560248201526044016110b1565b600e54826040013511156126b757600e54604080517f83f227e9000000000000000000000000000000000000000000000000000000008152600481019290925283013560248201526044016110b1565b600d548260c00135101561270857600d546040517f52be750b000000000000000000000000000000000000000000000000000000008152600481019190915260c083013560248201526044016110b1565b600c548260c00135111561275957600c546040517f83f227e9000000000000000000000000000000000000000000000000000000008152600481019190915260c083013560248201526044016110b1565b6006546001600160a01b031663b3b0e39a612777602085018561578b565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156127d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127f79190615b06565b61284657612808602083018361578b565b6040517fb4d5d7690000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024016110b1565b6006546001600160a01b0316632317e33e6060840135608085013561286e602087018761578b565b61287e6040880160208901615e31565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b168152600481019490945260248401929092526001600160a01b0316604483015215156064820152608401602060405180830381865afa1580156128ef573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129139190615b06565b61297657606082013560808301356129316040850160208601615e31565b6040517f4bb44f7f00000000000000000000000000000000000000000000000000000000815260048101939093526024830191909152151560448201526064016110b1565b60055461298b906001600160a01b0316615607565b6000546001546006546040517f67b083d40000000000000000000000000000000000000000000000000000000081529394506001600160a01b03808616946367b083d4946129ee9489943394610100909304831693918316921690600401615e4e565b600060405180830381600087803b158015612a0857600080fd5b505af1158015612a1c573d6000803e3d6000fd5b5050506001600160a01b0382166000818152601160205260409081902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000908116909317815560010180549092163317909155612a7f915083013542615b52565b6001600160a01b038216600081815260116020908152604080832060048101959095556203f480600590950194909455338083526012825293909120805460ff19166001179055612ad29085018561578b565b6001600160a01b03167f3316a4bda63688c184bbf39e3c0abc0a4f0c04ac2bcbcadb4597e056e48e7f678560400135866060013587608001358860a001358960c001358a6020016020810190612b289190615e31565b6040805196875260208701959095529385019290925260608401526080830152151560a082015260c00160405180910390a4919050565b6001600160a01b03808316600090815260116020908152604080832093851683526009840190915281205490919060ff1680612bb357506001600682015460ff166005811115612bb157612bb1615869565b145b15612bc15760009150612cf7565b6004600682015460ff166005811115612bdc57612bdc615869565b1480612c0057506000600682015460ff166005811115612bfe57612bfe615869565b145b15612c7d576001600160a01b038416600090815260136020526040902054612c3090670de0b6b3a7640000615f01565b6001600160a01b03841660009081526007830160205260409020546002830154612c5a9190615f01565b612c6c90670de0b6b3a7640000615f01565b612c769190615f3e565b9150612cf7565b6005600682015460ff166005811115612c9857612c98615869565b03612cf2576001600160a01b038416600090815260136020526040902054612cc890670de0b6b3a7640000615f01565b6001600160a01b03841660009081526007830160205260409020546003830154612c5a9190615f01565b600091505b5092915050565b6002546001600160a01b03163314612d3e57600254604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6001600160a01b038116612d7e576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600380547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517f7ce7ec0b50378fb6c0186ffb5f48325f6593fcb4ca4386f21861af3129188f5c90600090a250565b6003546001600160a01b03163314612e2057600354604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b612e286154dc565b6001600160a01b03811660009081526011602052604090206001600682015460ff166005811115612e5b57612e5b615869565b14612e92576040517f6d36408a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60068101805460ff1990811660031790915560018201546001600160a01b0390811660009081526012602052604080822080549094169093559151908416917f1a859cd6d744d14a7aa31ec6d24a7aa146272e8b7ceaca90635e47e01978af9291a25050565b6002546001600160a01b03163314612f3857600254604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b612f406154dc565b600b8190556040518181527fada2cde3c4a561f5c23e2fdbfb223e1f0d1ec7109b9811b32644e6e974d6631f90602001611358565b6002546001600160a01b03163314612fb557600254604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b612fbd6154dc565b6001811015612ff8576040517f1f2a200500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60088190556040518181527f7dd4ba3ef5fea9c2ce208e3358c40271c05848ed170f7f69e119764397c4b40b90602001611358565b6003546001600160a01b0316331461306d57600354604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6130756154dc565b6122d56156dc565b6002546001600160a01b031633146130bd57600254604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6001600160a01b038216600081815260126020908152604091829020805460ff191685151590811790915591519182527f449e12f29fe41627ebd01011c719955667b4df5c9c72d148fe27e0ff6dfdf0ef91016113ed565b6001600160a01b03811660009081526011602052604081208161313784611675565b50949550600294506131499350505050565b600683015460ff16600581111561316257613162615869565b14801561316d575080155b1561317c575060019392505050565b5060009392505050565b6002546001600160a01b031633146131c657600254604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6131ce6154dc565b6008548111613217576008546040517f52be750b0000000000000000000000000000000000000000000000000000000081526004810191909152602481018290526044016110b1565b60098190556040518181527f8ac6fedf0a404d729220682de310cf2e2d6f17dcc338cdfba39874ebb9994eb290602001611358565b6132546154dc565b6001600160a01b03851660009081526011602052604081209061327687611675565b50505050600185015492935050506001600160a01b031633148015906132a757506003546001600160a01b03163314155b156132dc576001820154604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6001600683015460ff1660058111156132f7576132f7615869565b1461332e576040517ff0c0e21000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b808514613367576040517ff9202d0b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60004661a4b103613416576040517f9b0f0f0c0000000000000000000000000000000000000000000000000000000081528715156004820152602481018790526044810186905284151560648201526001600160a01b03891690639b0f0f0c90349060840160206040518083038185885af11580156133ea573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019061340f9190615b06565b90506134b8565b46600a036134b857876001600160a01b031663c393d0e36040518163ffffffff1660e01b81526004016020604051808303816000875af115801561345e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134829190615b06565b6134b8576040517ff9202d0b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80156134ce5760068301805460ff191660021790555b60408051878152881515602082015290810186905281151560608201526001600160a01b038916907f10fe341e1741d7d3441096e3fac5b3aca87a6900380b8227a428d5753c9d74369060800160405180910390a25050505050505050565b6002546001600160a01b0316331461356d57600254604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b600680547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517f1df960924c08edb128ae4707e002ab3d24ba9322007a239ad35f91a20786ab0990600090a250565b6001600160a01b0381166000908152601160205260408120816135f184611675565b50949550600194506136039350505050565b600683015460ff16600581111561361c5761361c615869565b148015613627575080155b801561316d5750816005015482600401546136429190615b52565b42111561317c575060019392505050565b6001600160a01b03808316600090815260116020908152604080832093851683526007909301905220545b92915050565b336000818152601160205260409020805490916001600160a01b03909116146136d9576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002810182905560405182815233907f220317ba3e3fb18a406044bc828d93b7e79932f87d36079d105d45c0a98c894e906020016113ed565b6001600160a01b03811660009081526011602052604081206003612258565b6002546001600160a01b0316331461377157600254604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6137796154dc565b620f42408110156137c6576040517f52be750b000000000000000000000000000000000000000000000000000000008152662386f26fc100006004820152602481018290526044016110b1565b600d8190556040518181527ffaeb377e823a5620b92df1d4cf1fa60a9a3d2056324b71d0493ec132e482f5b690602001611358565b6138036154dc565b6001600160a01b0386811660009081526011602052604090206001810154909116331461385a576001810154604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b8415613a06576001600682015460ff16600581111561387b5761387b615869565b146138b2576040517f1da42b2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000546040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b038981166004830152600192610100900416906370a0823190602401602060405180830381865afa15801561391b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061393f9190615aed565b1015613977576040517f9ab109cb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60028101546040517fe325573100000000000000000000000000000000000000000000000000000000815287151560048201526024810185905260448101919091526001600160a01b0388169063e32557319034906064016000604051808303818588803b1580156139e857600080fd5b505af11580156139fc573d6000803e3d6000fd5b5050505050613b39565b6001600682015460ff166005811115613a2157613a21615869565b14158015613a4857506002600682015460ff166005811115613a4557613a45615869565b14155b15613a7f576040517f974da2dc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f9b0f0f0c0000000000000000000000000000000000000000000000000000000081528615156004820152602481018590526044810184905282151560648201526000906001600160a01b03891690639b0f0f0c90349060840160206040518083038185885af1158015613afa573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190613b1f9190615b06565b90508015613b375760068201805460ff191660021790555b505b604080518615158152602081018590526001600160a01b038916917fe076ebacb1a36aa582529f51828d818f426d49290b565c4b96aa2a8b5587f11b91016121b7565b613b846154dc565b6001600160a01b03828116600090815260116020526040902060018101549091163314801590613bbf57506003546001600160a01b03163314155b15613bf4576001810154604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6003546001600160a01b03163303613c525780600501548160040154613c1a9190615b52565b4211613c52576040517ff9202d0b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006005820155613c62836135cf565b613c98576040517ff9202d0b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517ff88d204700000000000000000000000000000000000000000000000000000000815260048101839052600160248201526000906001600160a01b0385169063f88d2047906044016020604051808303816000875af1158015613d02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d269190615aed565b600283018190556003830181905560068301805491925060049160ff1916600183021790555060018201546001600160a01b03908116600090815260126020526040808220805460ff1916905551918616917f4a808f5ebb4e18df4b677052792ca735ec5c9788cd7476f3a9cfd6cebfda74459190a250505050565b6002546001600160a01b03163314613de257600254604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6001600160a01b038116613e22576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517f853d105a12cf72456c97c86f4cbcec4744031d60d969811a1d34a308023b203f90600090a250565b6001600160a01b03811660009081526011602052604081206004612258565b6001600160a01b038116600090815260116020526040812081612258565b6002546001600160a01b03163314613f0157600254604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6001600160a01b038416613f41576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008315613f5a57506001600160a01b03851631613fe0565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b0387811660048301528416906370a0823190602401602060405180830381865afa158015613fb9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fdd9190615aed565b90505b80821115614024576040517f83f227e900000000000000000000000000000000000000000000000000000000815260048101829052602481018390526044016110b1565b6040517f0b5f319f0000000000000000000000000000000000000000000000000000000081526001600160a01b0386811660048301528515156024830152848116604483015260648201849052871690630b5f319f90608401600060405180830381600087803b15801561409757600080fd5b505af11580156140ab573d6000803e3d6000fd5b50505050826001600160a01b0316856001600160a01b0316876001600160a01b03167f2afa748f22c7778da03ee36f145a9b1a6a728d6053ae26cee5300b21d78a6ffc87866040516141099291909115158252602082015260400190565b60405180910390a4505050505050565b6002546001600160a01b0316331461415957600254604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6001600160a01b038116614199576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffff0000000000000000000000000000000000000000ff166101006001600160a01b03841690810291909117825560405190917f4f5d8f9f578d305dadec34d0cb4c1c417c27e5cdfea78e34b6bac920dfe13bb291a250565b6142086154dc565b6001600160a01b0380841660009081526011602052604090206001810154909116331461425f576001810154604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6000600682015460ff16600581111561427a5761427a615869565b146142b1576040517f1da42b2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806004015442106142ee576040517ff9202d0b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018160020154101561432d576040517f1f2a200500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60068101805460ff191660011790554260048083019190915560005460028301546040517fa9059cbb0000000000000000000000000000000000000000000000000000000081526001600160a01b038881169482019490945260248101919091526101009091049091169063a9059cbb906044016020604051808303816000875af11580156143c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143e49190615b06565b504661a4b10361447d5760028101546040517fe325573100000000000000000000000000000000000000000000000000000000815284151560048201526024810184905260448101919091526001600160a01b0385169063e32557319034906064016000604051808303818588803b15801561445f57600080fd5b505af1158015614473573d6000803e3d6000fd5b505050505061451f565b46600a0361451f57836001600160a01b031663350245c26040518163ffffffff1660e01b81526004016020604051808303816000875af11580156144c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144e99190615b06565b61451f576040517f79c099f200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080518415158152602081018490526001600160a01b038616917fe3d07a93ea2012896555861271ce9e1e6a9b8e731bff56b1baa4a823317a06be91015b60405180910390a250505050565b6002546001600160a01b031633146145ac57600254604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6145b46154dc565b620f424081116145fc576040517f83f227e9000000000000000000000000000000000000000000000000000000008152620f42406004820152602481018290526044016110b1565b600c8190556040518181527f629b53ebf66271b592438aa954e367dad37de9cd1c1a2b9dc4acade7e1ff9f4090602001611358565b6001600160a01b0382811660009081526011602052604090206001810154909116331480159061466c57506002546001600160a01b03163314155b156146a1576001810154604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6203f4808211156146ea576040517f83f227e90000000000000000000000000000000000000000000000000000000081526203f4806004820152602481018390526044016110b1565b600581018290556040518281526001600160a01b038416907fda21fe7cd8964fd0f9eda8f774bfbc66c4d534811de3b80cef219e9df79a6e01906020016119ce565b6003546001600160a01b0316331461476c57600354604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6147746154dc565b6001600160a01b038116600090815260116020526040812090600682015460ff1660058111156147a6576147a6615869565b146147dd576040517f4813c5bf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600201546000036148375780600401544211614832576004818101546040517f52be750b000000000000000000000000000000000000000000000000000000008152918201524260248201526044016110b1565b61488f565b8060050154816004015461484b9190615b52565b421161488f576004818101546040517f52be750b000000000000000000000000000000000000000000000000000000008152918201524260248201526044016110b1565b6006810180546004919060ff19166001836124a9565b6001600160a01b03811660009081526011602052604081206001612258565b6148cc6154dc565b6001600160a01b03838116600090815260116020526040902060018101549091163314614923576001810154604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b428160040154111561496d576004818101546040517f9d9d3b07000000000000000000000000000000000000000000000000000000008152918201524260248201526044016110b1565b6000600682015460ff16600581111561498857614988615869565b146149bf576040517f1da42b2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001816002015410156149fe576040517f1f2a200500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60068101805460ff1916600117905560005460028201546040517fa9059cbb0000000000000000000000000000000000000000000000000000000081526001600160a01b0387811660048301526024820192909252610100909204169063a9059cbb906044016020604051808303816000875af1158015614a83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614aa79190615b06565b504661a4b103614b405760028101546040517fe325573100000000000000000000000000000000000000000000000000000000815284151560048201526024810184905260448101919091526001600160a01b0385169063e32557319034906064016000604051808303818588803b158015614b2257600080fd5b505af1158015614b36573d6000803e3d6000fd5b5050505050614be2565b46600a03614be257836001600160a01b031663350245c26040518163ffffffff1660e01b81526004016020604051808303816000875af1158015614b88573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614bac9190615b06565b614be2576040517f79c099f200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080518415158152602081018490526001600160a01b038616917fbcee3379d56c5ea65c6957af10c3ecf663f19c42892076899323d08f024d2f45910161455e565b6002546001600160a01b03163314614c6557600254604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6001600160a01b038116614ca5576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517fc714d22a2f08b695f81e7c707058db484aa5b4d6b4c9fd64beb10fe85832f60890600090a250565b6002546001600160a01b03163314614d4757600254604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b614d4f6154dc565b600a8190556040518181527f0a29121cfa398b9e95ff515ed08281dc10b2522292fa7f18606cfaaa570ba4e990602001611358565b6002546001600160a01b03163314614dc457600254604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b614dcc6154dc565b610384811015614e13576040517f52be750b0000000000000000000000000000000000000000000000000000000081526103846004820152602481018290526044016110b1565b600e8190556040518181527f4f77c2c6810f043504ce09face8a21f7648e7ba1b991530f1580f1c4ddd102e890602001611358565b614e506154dc565b6001600160a01b03808216600090815260116020526040902060018101549091163314614ea7576001810154604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6000600682015460ff166005811115614ec257614ec2615869565b14614ef9576040517f1da42b2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600181600201541015614f38576040517f1f2a200500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600401544210614f75576040517ff9202d0b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b4260048201556040516001600160a01b038316907f351eaef6165bbd44916fe1e48715217d89ad4b425db112ea45c908be6446e43c90600090a25050565b614fbb6154dc565b4661a4b114615000576040517f9fba672f00000000000000000000000000000000000000000000000000000000815261a4b160048201524660248201526044016110b1565b6001600160a01b0381811660009081526011602052604090206001810154909116331480159061503b57506003546001600160a01b03163314155b15615070576001810154604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6002600682015460ff16600581111561508b5761508b615869565b146150c2576040517f1ba1720400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000806000846001600160a01b0316631fee5ccd6040518163ffffffff1660e01b81526004016060604051808303816000875af1158015615107573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061512b9190615f79565b60038701839055600687018054939650919450925060059160ff1916600183021790555060018401546001600160a01b039081166000908152601260209081526040808320805460ff191690559288168083526014825283832086905560158252918390208490558251868152908101859052918201839052907fe095746fb00b01d8b1f81c3f937f649fbd6ba123c09517dffe2167472021ea5c9060600160405180910390a25050505050565b6151e16154dc565b6001600160a01b0383811660009081526011602052604090206001810154909116331480159061521c57506003546001600160a01b03163314155b15615251576001810154604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b811561534f576001600682015460ff16600581111561527257615272615869565b146152a9576040517f1da42b2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60068101805460ff191690556040517ff88d20470000000000000000000000000000000000000000000000000000000081526004810184905282151560248201526000906001600160a01b0386169063f88d2047906044016020604051808303816000875af1158015615320573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906153449190615aed565b60028301555061548c565b6001600682015460ff16600581111561536a5761536a615869565b1415801561539157506002600682015460ff16600581111561538e5761538e615869565b14155b156153c8576040517f974da2dc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60068101805460ff199081166001908117909255818301546001600160a01b0390811660009081526012602052604090819020805490931690931790915590517ff88d20470000000000000000000000000000000000000000000000000000000081526004810185905283151560248201529085169063f88d2047906044016020604051808303816000875af1158015615466573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061548a9190615aed565b505b6002810154604080518581528415156020820152908101919091526001600160a01b038516907f610fd83131a01a963438707dc05328b654bad7cab052f0d9625cacefb54000a59060600161455e565b60005460ff16156122d5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a207061757365640000000000000000000000000000000060448201526064016110b1565b60005460ff166122d5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f742070617573656400000000000000000000000060448201526064016110b1565b6155bd615549565b6000805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b60006040517f3d602d80600a3d3981f3363d3d373d3d3d363d7300000000000000000000000081528260601b60148201527f5af43d82803e903d91602b57fd5bf3000000000000000000000000000000000060288201526037816000f09150506001600160a01b0381166156d7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f455243313136373a20637265617465206661696c65640000000000000000000060448201526064016110b1565b919050565b6156e46154dc565b6000805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586155ea3390565b6001600160a01b038116811461572e57600080fd5b50565b60008060006060848603121561574657600080fd5b833561575181615719565b9250602084013561576181615719565b929592945050506040919091013590565b60006020828403121561578457600080fd5b5035919050565b60006020828403121561579d57600080fd5b81356157a881615719565b9392505050565b600080604083850312156157c257600080fd5b82356157cd81615719565b946020939093013593505050565b801515811461572e57600080fd5b600080600080600060a0868803121561580157600080fd5b853561580c81615719565b9450602086013561581c816157db565b93506040860135925060608601359150608086013561583a816157db565b809150509295509295909350565b60006020828403121561585a57600080fd5b8135600681106157a857600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600681106158cf577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b6020810161367e8284615898565b600060e0828403121561227f57600080fd5b6000806040838503121561590657600080fd5b823561591181615719565b9150602083013561592181615719565b809150509250929050565b6001600160a01b0388811682528716602082015260408101869052606081018590526080810184905260a0810183905260e0810161596d60c0830184615898565b98975050505050505050565b6000806040838503121561598c57600080fd5b823561599781615719565b91506020830135615921816157db565b60008060008060008060c087890312156159c057600080fd5b86356159cb81615719565b955060208701356159db816157db565b945060408701356159eb816157db565b9350606087013592506080870135915060a0870135615a09816157db565b809150509295509295509295565b600080600080600060a08688031215615a2f57600080fd5b8535615a3a81615719565b94506020860135615a4a81615719565b93506040860135615a5a816157db565b92506060860135615a6a81615719565b949793965091946080013592915050565b600080600060608486031215615a9057600080fd5b8335615a9b81615719565b92506020840135615761816157db565b600080600060608486031215615ac057600080fd5b8335615acb81615719565b9250602084013591506040840135615ae2816157db565b809150509250925092565b600060208284031215615aff57600080fd5b5051919050565b600060208284031215615b1857600080fd5b81516157a8816157db565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008219821115615b6557615b65615b23565b500190565b6000808312837f800000000000000000000000000000000000000000000000000000000000000001831281151615615ba457615ba4615b23565b837f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff018313811615615bd857615bd8615b23565b50500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715615c5457615c54615bde565b604052919050565b600060e08284031215615c6e57600080fd5b60405160e0810181811067ffffffffffffffff82111715615c9157615c91615bde565b6040528251615c9f81615719565b81526020830151615caf816157db565b8060208301525060408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c08201528091505092915050565b60006020808385031215615d0557600080fd5b825167ffffffffffffffff80821115615d1d57600080fd5b818501915085601f830112615d3157600080fd5b815181811115615d4357615d43615bde565b8060051b9150615d54848301615c0d565b8181529183018401918481019088841115615d6e57600080fd5b938501935b8385101561596d5784519250615d8883615719565b8282529385019390850190615d73565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600080600080600080600080610100898b031215615de457600080fd5b885197506020890151965060408901519550606089015194506080890151935060a0890151925060c0890151615e19816157db565b8092505060e089015190509295985092959890939650565b600060208284031215615e4357600080fd5b81356157a8816157db565b61016081018635615e5e81615719565b6001600160a01b031682526020870135615e77816157db565b80151560208401525060408701356040830152606087013560608301526080870135608083015260a087013560a083015260c087013560c0830152615ec760e08301876001600160a01b03169052565b6001600160a01b0385166101008301526001600160a01b0384166101208301526001600160a01b0383166101408301529695505050505050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615615f3957615f39615b23565b500290565b600082615f74577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b600080600060608486031215615f8e57600080fd5b835192506020840151915060408401519050925092509256fea264697066735822122052b9a8682a6e67e8d07e383c283240df048d8e32f72687e0e88153dafcdd466264736f6c634300080f0033000000000000000000000000bac2e501d529160ba06fc2092c94e010d56d42c200000000000000000000000031eea3a0cbd74463071a1211f83ec535c67d3212000000000000000000000000000000000000000000000000000000000bebc2000000000000000000000000000000000000000000000000000000000001312d000000000000000000000000000000000000000000000000000000000002faf0800000000000000000000000000000000000000000000000000000000000989680000000000000000000000000ff970a61a04b1ca14834a43f5de4533ebddb5cc800000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab10000000000000000000000004df53b363850b1bb33e34b6dfebeb519b3e57641000000000000000000000000295d70125e0c6437a3915fe7a6ac7205bacc2e91

Deployed Bytecode

0x6080604052600436106105585760003560e01c80638f725541116102ca578063ccf362c811610179578063e1f8c1be116100d6578063f41bb5bf1161008a578063f7f2b25a1161006f578063f7f2b25a14611015578063f851a44014611035578063faee7a2b1461105557600080fd5b8063f41bb5bf14610fd5578063f6fa527a14610ff557600080fd5b8063ed3b914c116100bb578063ed3b914c14610f82578063f0f4426014610f95578063f217c92914610fb557600080fd5b8063e1f8c1be14610ed1578063ea49ee6f14610f3857600080fd5b8063d7a4056f1161012d578063dadb98ed11610112578063dadb98ed14610e6e578063dcf844a714610e8e578063dfabb02614610ebb57600080fd5b8063d7a4056f14610e38578063d8b6d25214610e5857600080fd5b8063d3127e631161015e578063d3127e6314610dd8578063d4fc42c614610df8578063d736296514610e1857600080fd5b8063ccf362c814610d78578063d0b272a114610dc557600080fd5b8063ac2e625f11610227578063be39cce2116101db578063c374d2d1116101c0578063c374d2d114610d18578063ca3b215314610d38578063cb14687914610d5857600080fd5b8063be39cce214610ccb578063c342da0c14610cf857600080fd5b8063b0e21e8a1161020c578063b0e21e8a14610c75578063b75502b114610c8b578063b8d1452f14610cab57600080fd5b8063ac2e625f14610c4c578063ae3302c214610c5f57600080fd5b80639d2629631161027e578063a0914e6a11610263578063a0914e6a14610bec578063a3b3f60614610c0c578063a548929714610c2c57600080fd5b80639d26296314610bac5780639f19165914610bcc57600080fd5b806391b1cb56116102af57806391b1cb5614610b635780639598da7f14610b765780639c7632fc14610b9657600080fd5b80638f72554114610b2d5780638ff88f1714610b4d57600080fd5b80635c943880116104265780637806615f1161038357806387c2b5b3116103375780638c21cd521161031c5780638c21cd5214610ad75780638c43d73914610af75780638da5cb5b14610b0d57600080fd5b806387c2b5b314610a8a57806389a9a7ee14610ab757600080fd5b80637d109647116103685780637d10964714610a255780637fbb108614610a555780638456cb5914610a7557600080fd5b80637806615f146109e5578063787dce3d14610a0557600080fd5b80636b3d3d2c116103da578063704b6c02116103bf578063704b6c021461092657806374d711f1146109465780637776b1a71461096657600080fd5b80636b3d3d2c146108e65780636ef178bf1461090657600080fd5b80635fe633bc1161040b5780635fe633bc1461086e57806361d027b31461088e5780636943b017146108c657600080fd5b80635c943880146108405780635c975abb1461085657600080fd5b80631e83409a116104d45780633f4ba83a116104885780634cd2745a1161046d5780634cd2745a146107c15780634d298a07146107e1578063541c7480146107f757600080fd5b80633f4ba83a1461078c578063456f44de146107a157600080fd5b8063279847f3116104b9578063279847f3146107295780632d5aa3ad1461073c5780633ebf64741461075c57600080fd5b80631e83409a146106e557806320f6f76f1461070557600080fd5b806313af40351161052b57806316c197391161051057806316c197391461064e5780631b9a91a4146106a55780631d27bdca146106c557600080fd5b806313af4035146105df57806313ea7c89146105ff57600080fd5b806301e336671461055d57806307c5a0ff1461057f578063082dbade1461059f5780630a19a012146105bf575b600080fd5b34801561056957600080fd5b5061057d610578366004615731565b611075565b005b34801561058b57600080fd5b5061057d61059a366004615772565b6112a4565b3480156105ab57600080fd5b5061057d6105ba366004615772565b611363565b3480156105cb57600080fd5b5061057d6105da366004615772565b6113f9565b3480156105eb57600080fd5b5061057d6105fa36600461578b565b6114bf565b34801561060b57600080fd5b5061061f61061a36600461578b565b6115a1565b6040805195865260208601949094529284019190915260608301521515608082015260a0015b60405180910390f35b34801561065a57600080fd5b5061066e61066936600461578b565b611675565b604080519788526020880196909652948601939093526060850191909152608084015260a0830152151560c082015260e001610645565b3480156106b157600080fd5b5061057d6106c03660046157af565b611897565b3480156106d157600080fd5b5061057d6106e03660046157af565b6119db565b3480156106f157600080fd5b5061057d61070036600461578b565b611cd9565b34801561071157600080fd5b5061071b600d5481565b604051908152602001610645565b61057d6107373660046157e9565b611eb6565b34801561074857600080fd5b5061057d610757366004615772565b6121c8565b34801561076857600080fd5b5061077c61077736600461578b565b61223d565b6040519015158152602001610645565b34801561079857600080fd5b5061057d612285565b3480156107ad57600080fd5b5061057d6107bc366004615848565b6122d7565b3480156107cd57600080fd5b5061057d6107dc36600461578b565b61238b565b3480156107ed57600080fd5b5061071b60085481565b34801561080357600080fd5b5061083361081236600461578b565b6001600160a01b031660009081526011602052604090206006015460ff1690565b60405161064591906158d3565b34801561084c57600080fd5b5061071b600e5481565b34801561086257600080fd5b5060005460ff1661077c565b34801561087a57600080fd5b5061057d61088936600461578b565b612502565b34801561089a57600080fd5b506004546108ae906001600160a01b031681565b6040516001600160a01b039091168152602001610645565b3480156108d257600080fd5b5061077c6108e136600461578b565b6125a4565b3480156108f257600080fd5b506108ae6109013660046158e1565b6125c3565b34801561091257600080fd5b5061071b6109213660046158f3565b612b5f565b34801561093257600080fd5b5061057d61094136600461578b565b612cfe565b34801561095257600080fd5b5061057d61096136600461578b565b612de0565b34801561097257600080fd5b506109d261098136600461578b565b6001600160a01b039081166000908152601160205260409020805460018201546002830154600384015460048501546005860154600690960154948716979390961695919490939192909160ff1690565b604051610645979695949392919061592c565b3480156109f157600080fd5b506005546108ae906001600160a01b031681565b348015610a1157600080fd5b5061057d610a20366004615772565b612ef8565b348015610a3157600080fd5b5061077c610a4036600461578b565b60126020526000908152604090205460ff1681565b348015610a6157600080fd5b5061057d610a70366004615772565b612f75565b348015610a8157600080fd5b5061057d61302d565b348015610a9657600080fd5b5061071b610aa536600461578b565b60146020526000908152604090205481565b348015610ac357600080fd5b5061057d610ad2366004615979565b61307d565b348015610ae357600080fd5b5061077c610af236600461578b565b613115565b348015610b0357600080fd5b5061071b60075481565b348015610b1957600080fd5b506002546108ae906001600160a01b031681565b348015610b3957600080fd5b5061057d610b48366004615772565b613186565b348015610b5957600080fd5b5061071b600f5481565b61057d610b713660046157e9565b61324c565b348015610b8257600080fd5b5061057d610b9136600461578b565b61352d565b348015610ba257600080fd5b5061071b600a5481565b348015610bb857600080fd5b5061077c610bc736600461578b565b6135cf565b348015610bd857600080fd5b5061071b610be73660046158f3565b613653565b348015610bf857600080fd5b5061057d610c07366004615772565b613684565b348015610c1857600080fd5b5061077c610c2736600461578b565b613712565b348015610c3857600080fd5b5061057d610c47366004615772565b613731565b61057d610c5a3660046159a7565b6137fb565b348015610c6b57600080fd5b5061071b600c5481565b348015610c8157600080fd5b5061071b600b5481565b348015610c9757600080fd5b5061057d610ca63660046157af565b613b7c565b348015610cb757600080fd5b5061057d610cc636600461578b565b613da2565b348015610cd757600080fd5b5061071b610ce636600461578b565b60136020526000908152604090205481565b348015610d0457600080fd5b5061077c610d1336600461578b565b613e84565b348015610d2457600080fd5b5061077c610d3336600461578b565b613ea3565b348015610d4457600080fd5b5061057d610d53366004615a17565b613ec1565b348015610d6457600080fd5b5061057d610d7336600461578b565b614119565b348015610d8457600080fd5b5061077c610d933660046158f3565b6001600160a01b0391821660009081526011602090815260408083209390941682526009909201909152205460ff1690565b61057d610dd3366004615a7b565b614200565b348015610de457600080fd5b5061057d610df3366004615772565b61456c565b348015610e0457600080fd5b506006546108ae906001600160a01b031681565b348015610e2457600080fd5b5061057d610e333660046157af565b614631565b348015610e4457600080fd5b5061057d610e5336600461578b565b61472c565b348015610e6457600080fd5b5061071b60105481565b348015610e7a57600080fd5b5061077c610e8936600461578b565b6148a5565b348015610e9a57600080fd5b5061071b610ea936600461578b565b60156020526000908152604090205481565b348015610ec757600080fd5b5061071b60095481565b348015610edd57600080fd5b506109d2610eec36600461578b565b60116020526000908152604090208054600182015460028301546003840154600485015460058601546006909601546001600160a01b0395861696959094169492939192909160ff1687565b348015610f4457600080fd5b5061071b610f533660046158f3565b6001600160a01b0391821660009081526011602090815260408083209390941682526008909201909152205490565b61057d610f90366004615a7b565b6148c4565b348015610fa157600080fd5b5061057d610fb036600461578b565b614c25565b348015610fc157600080fd5b5061057d610fd0366004615772565b614d07565b348015610fe157600080fd5b5061057d610ff0366004615772565b614d84565b34801561100157600080fd5b5061057d61101036600461578b565b614e48565b34801561102157600080fd5b5061057d61103036600461578b565b614fb3565b34801561104157600080fd5b506003546108ae906001600160a01b031681565b34801561106157600080fd5b5061057d611070366004615aab565b6151d9565b6002546001600160a01b031633146110ba57600254604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044015b60405180910390fd5b6001600160a01b0382166110fa576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000906001600160a01b038516906370a0823190602401602060405180830381865afa15801561115a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061117e9190615aed565b9050808211156111c4576040517f83f227e900000000000000000000000000000000000000000000000000000000815260048101829052602481018390526044016110b1565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000081526001600160a01b0384811660048301526024820184905285169063a9059cbb906044016020604051808303816000875af115801561122c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112509190615b06565b50826001600160a01b0316846001600160a01b03167f037238854fe57fbf51f09946f854fc3916fe83938d6521f09bd05463839f13048460405161129691815260200190565b60405180910390a350505050565b6002546001600160a01b031633146112e457600254604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6112ec6154dc565b6001811015611327576040517f1f2a200500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60078190556040518181527fc968c2b2d4bd824c9eeae67e73329723fd6055c7f5c7880094263ec6e2efe0c6906020015b60405180910390a150565b336000818152601160205260409020805490916001600160a01b03909116146113b8576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6003810182905560405182815233907fec9e3aa9b0e25af4ea15e340b3c4e013cb69d0529dcb1ddf9a735cc4807c3aae906020015b60405180910390a25050565b6002546001600160a01b0316331461143957600254604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6114416154dc565b6201518081101561148a576040517f52be750b000000000000000000000000000000000000000000000000000000008152620151806004820152602481018290526044016110b1565b600f8190556040518181527f8cf6167c03aff0cae83560b208602b7fb5c79d5d29336d97c23f087d12c163ad90602001611358565b6002546001600160a01b031633146114ff57600254604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6001600160a01b03811661153f576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517fa2ea9883a321a3e97b8266c2b078bfeec6d50c711ed71f874a90d500ae2eaf3690600090a250565b6001600160a01b038116600090815260116020526040812081908190819081906005600682015460ff1660058111156115dc576115dc615869565b036115e657600191505b6001600160a01b03871660009081526014602090815260408083205460158352818420546013909352922054600384015492985090965090869061162b908990615b52565b6116359190615b52565b61163f9190615b6a565b6001600160a01b038816600090815260136020526040902054600383015491955061166991615b6a565b92505091939590929450565b600080600080600080600080886001600160a01b031663e113c9b46040518163ffffffff1660e01b815260040160e060405180830381865afa1580156116bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116e39190615c5c565b90506000600660009054906101000a90046001600160a01b03166001600160a01b031663191622ff6040518163ffffffff1660e01b8152600401600060405180830381865afa15801561173a573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526117809190810190615cf2565b60008151811061179257611792615d98565b60200260200101519050806001600160a01b0316634a3f088d8b84602001516117cb5760005461010090046001600160a01b03166117ce565b84515b8551602087015160405160e086901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b039485166004820152928416602484015292166044820152901515606482015260840161010060405180830381865afa158015611849573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061186d9190615dc7565b50809950819a50829b50839c50849d50859e50869f50505050505050505050919395979092949650565b6002546001600160a01b031633146118d757600254604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6001600160a01b038216611917576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b478082111561195c576040517f83f227e900000000000000000000000000000000000000000000000000000000815260048101829052602481018390526044016110b1565b6040516001600160a01b0384169083156108fc029084906000818181858888f19350505050158015611992573d6000803e3d6000fd5b50826001600160a01b03167fccbd99ba6da8f29b2a4f65e474e3c3973564d356c162c08d45f3dc7f0cb5b3aa836040516119ce91815260200190565b60405180910390a2505050565b6119e36154dc565b6001600160a01b03821660009081526011602052604090206004810154421115611a45576004818101546040517f83f227e9000000000000000000000000000000000000000000000000000000008152918201524260248201526044016110b1565b600854821015611a8f576008546040517f52be750b0000000000000000000000000000000000000000000000000000000081526004810191909152602481018390526044016110b1565b600954336000908152600783016020526040902054611aaf908490615b52565b1115611b1057600954336000908152600783016020526040902054611ad5908490615b52565b6040517f83f227e9000000000000000000000000000000000000000000000000000000008152600481019290925260248201526044016110b1565b6000600682015460ff166005811115611b2b57611b2b615869565b14611b62576040517f1da42b2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600754828260020154611b759190615b52565b1115611b8e57600754828260020154611ad59190615b52565b81816002016000828254611ba29190615b52565b909155505033600090815260078201602052604081208054849290611bc8908490615b52565b90915550506001600160a01b03831660009081526013602052604081208054849290611bf5908490615b52565b90915550506000546040517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018490526101009091046001600160a01b0316906323b872dd906064016020604051808303816000875af1158015611c6e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c929190615b06565b5060405182815233906001600160a01b038516907f6de21c38099746d11a6455c0eacd00c03c175731ddded0ca3f86a70e5ee17b5a906020015b60405180910390a3505050565b611ce16154dc565b6001600160a01b03811660009081526011602052604090206005600682015460ff166005811115611d1457611d14615869565b14158015611d3b57506004600682015460ff166005811115611d3857611d38615869565b14155b15611d72576040517f1ba1720400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611d7e8333612b5f565b90506001811015611dbb576040517f9ab109cb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360008181526009840160209081526040808320805460ff1916600117905560088601909152808220849055905490517fa9059cbb00000000000000000000000000000000000000000000000000000000815260048101929092526024820183905261010090046001600160a01b03169063a9059cbb906044016020604051808303816000875af1158015611e54573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e789190615b06565b506040518181526001600160a01b0384169033907ff7a40077ff7a04c7e61f6f26fb13774259ddf1b6bce9ecf26a8276cdd399268390602001611ccc565b611ebe6154dc565b6001600160a01b038516600090815260116020526040812090611ee087611675565b5050505050509050600f544211611f3057600f546040517f52be750b00000000000000000000000000000000000000000000000000000000815260048101919091524260248201526044016110b1565b6003546001600160a01b03163314611f74576040517ff9202d0b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002600683015460ff166005811115611f8f57611f8f615869565b14158015611fb657506001600683015460ff166005811115611fb357611fb3615869565b14155b15611fed576040517ff9202d0b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001811015612028576040517ff0c0e21000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b85156120bf576040517ff88d204700000000000000000000000000000000000000000000000000000000815260048101869052600060248201819052906001600160a01b0389169063f88d2047906044016020604051808303816000875af1158015612098573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120bc9190615aed565b50505b6040517f9b0f0f0c00000000000000000000000000000000000000000000000000000000815260006004820152602481018290526044810185905283151560648201526001600160a01b03881690639b0f0f0c90349060840160206040518083038185885af1158015612136573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019061215b9190615b06565b5060068201805460ff191660021790556040805182815260006020820152908101859052600160608201526001600160a01b038816907f10fe341e1741d7d3441096e3fac5b3aca87a6900380b8227a428d5753c9d7436906080015b60405180910390a250505050505050565b6002546001600160a01b0316331461220857600254604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b60108190556040518181527f0770d360699a0d8cb23e6911d959e5433052103c9fef4ea9dcca7ea0c05d995390602001611358565b6001600160a01b038116600090815260116020526040812060055b600682015460ff16600581111561227157612271615869565b0361227f5750600192915050565b50919050565b6003546001600160a01b031633146122c557600354604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6122cd615549565b6122d56155b5565b565b336000818152601160205260409020805490916001600160a01b039091161461232c576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60068101805483919060ff1916600183600581111561234d5761234d615869565b0217905550336001600160a01b03167fa35440f710f530b15483dadda015cac6bac4a69bf1a1cdad95d4ae67ae8c0480836040516113ed91906158d3565b6123936154dc565b6001600160a01b038181166000908152601160205260409020600181015490911633146123ea576001810154604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6000600682015460ff16600581111561240557612405615869565b1461243c576040517f4813c5bf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806005015481600401546124509190615b52565b421115612489576040517ff9202d0b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006005820181905560048083019190915560068201805460ff19166001835b021790555060018101546001600160a01b03908116600090815260126020526040808220805460ff1916905551918416917f4a808f5ebb4e18df4b677052792ca735ec5c9788cd7476f3a9cfd6cebfda74459190a25050565b6002546001600160a01b0316331461254257600254604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b600580547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517f9b0f1509d9404d6b879d0b12becc0b301899423cdcc45fa855aa25c89c8b95b790600090a250565b6001600160a01b03811660009081526011602052604081206002612258565b60006125cd6154dc565b3360009081526012602052604090205460ff1615612619576040517f9ba436c40000000000000000000000000000000000000000000000000000000081523360048201526024016110b1565b6103848260400135101561266757604080517f52be750b00000000000000000000000000000000000000000000000000000000815261038460048201529083013560248201526044016110b1565b600e54826040013511156126b757600e54604080517f83f227e9000000000000000000000000000000000000000000000000000000008152600481019290925283013560248201526044016110b1565b600d548260c00135101561270857600d546040517f52be750b000000000000000000000000000000000000000000000000000000008152600481019190915260c083013560248201526044016110b1565b600c548260c00135111561275957600c546040517f83f227e9000000000000000000000000000000000000000000000000000000008152600481019190915260c083013560248201526044016110b1565b6006546001600160a01b031663b3b0e39a612777602085018561578b565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156127d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127f79190615b06565b61284657612808602083018361578b565b6040517fb4d5d7690000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024016110b1565b6006546001600160a01b0316632317e33e6060840135608085013561286e602087018761578b565b61287e6040880160208901615e31565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b168152600481019490945260248401929092526001600160a01b0316604483015215156064820152608401602060405180830381865afa1580156128ef573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129139190615b06565b61297657606082013560808301356129316040850160208601615e31565b6040517f4bb44f7f00000000000000000000000000000000000000000000000000000000815260048101939093526024830191909152151560448201526064016110b1565b60055461298b906001600160a01b0316615607565b6000546001546006546040517f67b083d40000000000000000000000000000000000000000000000000000000081529394506001600160a01b03808616946367b083d4946129ee9489943394610100909304831693918316921690600401615e4e565b600060405180830381600087803b158015612a0857600080fd5b505af1158015612a1c573d6000803e3d6000fd5b5050506001600160a01b0382166000818152601160205260409081902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000908116909317815560010180549092163317909155612a7f915083013542615b52565b6001600160a01b038216600081815260116020908152604080832060048101959095556203f480600590950194909455338083526012825293909120805460ff19166001179055612ad29085018561578b565b6001600160a01b03167f3316a4bda63688c184bbf39e3c0abc0a4f0c04ac2bcbcadb4597e056e48e7f678560400135866060013587608001358860a001358960c001358a6020016020810190612b289190615e31565b6040805196875260208701959095529385019290925260608401526080830152151560a082015260c00160405180910390a4919050565b6001600160a01b03808316600090815260116020908152604080832093851683526009840190915281205490919060ff1680612bb357506001600682015460ff166005811115612bb157612bb1615869565b145b15612bc15760009150612cf7565b6004600682015460ff166005811115612bdc57612bdc615869565b1480612c0057506000600682015460ff166005811115612bfe57612bfe615869565b145b15612c7d576001600160a01b038416600090815260136020526040902054612c3090670de0b6b3a7640000615f01565b6001600160a01b03841660009081526007830160205260409020546002830154612c5a9190615f01565b612c6c90670de0b6b3a7640000615f01565b612c769190615f3e565b9150612cf7565b6005600682015460ff166005811115612c9857612c98615869565b03612cf2576001600160a01b038416600090815260136020526040902054612cc890670de0b6b3a7640000615f01565b6001600160a01b03841660009081526007830160205260409020546003830154612c5a9190615f01565b600091505b5092915050565b6002546001600160a01b03163314612d3e57600254604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6001600160a01b038116612d7e576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600380547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517f7ce7ec0b50378fb6c0186ffb5f48325f6593fcb4ca4386f21861af3129188f5c90600090a250565b6003546001600160a01b03163314612e2057600354604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b612e286154dc565b6001600160a01b03811660009081526011602052604090206001600682015460ff166005811115612e5b57612e5b615869565b14612e92576040517f6d36408a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60068101805460ff1990811660031790915560018201546001600160a01b0390811660009081526012602052604080822080549094169093559151908416917f1a859cd6d744d14a7aa31ec6d24a7aa146272e8b7ceaca90635e47e01978af9291a25050565b6002546001600160a01b03163314612f3857600254604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b612f406154dc565b600b8190556040518181527fada2cde3c4a561f5c23e2fdbfb223e1f0d1ec7109b9811b32644e6e974d6631f90602001611358565b6002546001600160a01b03163314612fb557600254604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b612fbd6154dc565b6001811015612ff8576040517f1f2a200500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60088190556040518181527f7dd4ba3ef5fea9c2ce208e3358c40271c05848ed170f7f69e119764397c4b40b90602001611358565b6003546001600160a01b0316331461306d57600354604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6130756154dc565b6122d56156dc565b6002546001600160a01b031633146130bd57600254604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6001600160a01b038216600081815260126020908152604091829020805460ff191685151590811790915591519182527f449e12f29fe41627ebd01011c719955667b4df5c9c72d148fe27e0ff6dfdf0ef91016113ed565b6001600160a01b03811660009081526011602052604081208161313784611675565b50949550600294506131499350505050565b600683015460ff16600581111561316257613162615869565b14801561316d575080155b1561317c575060019392505050565b5060009392505050565b6002546001600160a01b031633146131c657600254604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6131ce6154dc565b6008548111613217576008546040517f52be750b0000000000000000000000000000000000000000000000000000000081526004810191909152602481018290526044016110b1565b60098190556040518181527f8ac6fedf0a404d729220682de310cf2e2d6f17dcc338cdfba39874ebb9994eb290602001611358565b6132546154dc565b6001600160a01b03851660009081526011602052604081209061327687611675565b50505050600185015492935050506001600160a01b031633148015906132a757506003546001600160a01b03163314155b156132dc576001820154604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6001600683015460ff1660058111156132f7576132f7615869565b1461332e576040517ff0c0e21000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b808514613367576040517ff9202d0b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60004661a4b103613416576040517f9b0f0f0c0000000000000000000000000000000000000000000000000000000081528715156004820152602481018790526044810186905284151560648201526001600160a01b03891690639b0f0f0c90349060840160206040518083038185885af11580156133ea573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019061340f9190615b06565b90506134b8565b46600a036134b857876001600160a01b031663c393d0e36040518163ffffffff1660e01b81526004016020604051808303816000875af115801561345e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134829190615b06565b6134b8576040517ff9202d0b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80156134ce5760068301805460ff191660021790555b60408051878152881515602082015290810186905281151560608201526001600160a01b038916907f10fe341e1741d7d3441096e3fac5b3aca87a6900380b8227a428d5753c9d74369060800160405180910390a25050505050505050565b6002546001600160a01b0316331461356d57600254604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b600680547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517f1df960924c08edb128ae4707e002ab3d24ba9322007a239ad35f91a20786ab0990600090a250565b6001600160a01b0381166000908152601160205260408120816135f184611675565b50949550600194506136039350505050565b600683015460ff16600581111561361c5761361c615869565b148015613627575080155b801561316d5750816005015482600401546136429190615b52565b42111561317c575060019392505050565b6001600160a01b03808316600090815260116020908152604080832093851683526007909301905220545b92915050565b336000818152601160205260409020805490916001600160a01b03909116146136d9576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002810182905560405182815233907f220317ba3e3fb18a406044bc828d93b7e79932f87d36079d105d45c0a98c894e906020016113ed565b6001600160a01b03811660009081526011602052604081206003612258565b6002546001600160a01b0316331461377157600254604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6137796154dc565b620f42408110156137c6576040517f52be750b000000000000000000000000000000000000000000000000000000008152662386f26fc100006004820152602481018290526044016110b1565b600d8190556040518181527ffaeb377e823a5620b92df1d4cf1fa60a9a3d2056324b71d0493ec132e482f5b690602001611358565b6138036154dc565b6001600160a01b0386811660009081526011602052604090206001810154909116331461385a576001810154604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b8415613a06576001600682015460ff16600581111561387b5761387b615869565b146138b2576040517f1da42b2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000546040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b038981166004830152600192610100900416906370a0823190602401602060405180830381865afa15801561391b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061393f9190615aed565b1015613977576040517f9ab109cb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60028101546040517fe325573100000000000000000000000000000000000000000000000000000000815287151560048201526024810185905260448101919091526001600160a01b0388169063e32557319034906064016000604051808303818588803b1580156139e857600080fd5b505af11580156139fc573d6000803e3d6000fd5b5050505050613b39565b6001600682015460ff166005811115613a2157613a21615869565b14158015613a4857506002600682015460ff166005811115613a4557613a45615869565b14155b15613a7f576040517f974da2dc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f9b0f0f0c0000000000000000000000000000000000000000000000000000000081528615156004820152602481018590526044810184905282151560648201526000906001600160a01b03891690639b0f0f0c90349060840160206040518083038185885af1158015613afa573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190613b1f9190615b06565b90508015613b375760068201805460ff191660021790555b505b604080518615158152602081018590526001600160a01b038916917fe076ebacb1a36aa582529f51828d818f426d49290b565c4b96aa2a8b5587f11b91016121b7565b613b846154dc565b6001600160a01b03828116600090815260116020526040902060018101549091163314801590613bbf57506003546001600160a01b03163314155b15613bf4576001810154604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6003546001600160a01b03163303613c525780600501548160040154613c1a9190615b52565b4211613c52576040517ff9202d0b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006005820155613c62836135cf565b613c98576040517ff9202d0b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517ff88d204700000000000000000000000000000000000000000000000000000000815260048101839052600160248201526000906001600160a01b0385169063f88d2047906044016020604051808303816000875af1158015613d02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d269190615aed565b600283018190556003830181905560068301805491925060049160ff1916600183021790555060018201546001600160a01b03908116600090815260126020526040808220805460ff1916905551918616917f4a808f5ebb4e18df4b677052792ca735ec5c9788cd7476f3a9cfd6cebfda74459190a250505050565b6002546001600160a01b03163314613de257600254604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6001600160a01b038116613e22576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517f853d105a12cf72456c97c86f4cbcec4744031d60d969811a1d34a308023b203f90600090a250565b6001600160a01b03811660009081526011602052604081206004612258565b6001600160a01b038116600090815260116020526040812081612258565b6002546001600160a01b03163314613f0157600254604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6001600160a01b038416613f41576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008315613f5a57506001600160a01b03851631613fe0565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b0387811660048301528416906370a0823190602401602060405180830381865afa158015613fb9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fdd9190615aed565b90505b80821115614024576040517f83f227e900000000000000000000000000000000000000000000000000000000815260048101829052602481018390526044016110b1565b6040517f0b5f319f0000000000000000000000000000000000000000000000000000000081526001600160a01b0386811660048301528515156024830152848116604483015260648201849052871690630b5f319f90608401600060405180830381600087803b15801561409757600080fd5b505af11580156140ab573d6000803e3d6000fd5b50505050826001600160a01b0316856001600160a01b0316876001600160a01b03167f2afa748f22c7778da03ee36f145a9b1a6a728d6053ae26cee5300b21d78a6ffc87866040516141099291909115158252602082015260400190565b60405180910390a4505050505050565b6002546001600160a01b0316331461415957600254604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6001600160a01b038116614199576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffff0000000000000000000000000000000000000000ff166101006001600160a01b03841690810291909117825560405190917f4f5d8f9f578d305dadec34d0cb4c1c417c27e5cdfea78e34b6bac920dfe13bb291a250565b6142086154dc565b6001600160a01b0380841660009081526011602052604090206001810154909116331461425f576001810154604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6000600682015460ff16600581111561427a5761427a615869565b146142b1576040517f1da42b2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806004015442106142ee576040517ff9202d0b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018160020154101561432d576040517f1f2a200500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60068101805460ff191660011790554260048083019190915560005460028301546040517fa9059cbb0000000000000000000000000000000000000000000000000000000081526001600160a01b038881169482019490945260248101919091526101009091049091169063a9059cbb906044016020604051808303816000875af11580156143c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143e49190615b06565b504661a4b10361447d5760028101546040517fe325573100000000000000000000000000000000000000000000000000000000815284151560048201526024810184905260448101919091526001600160a01b0385169063e32557319034906064016000604051808303818588803b15801561445f57600080fd5b505af1158015614473573d6000803e3d6000fd5b505050505061451f565b46600a0361451f57836001600160a01b031663350245c26040518163ffffffff1660e01b81526004016020604051808303816000875af11580156144c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144e99190615b06565b61451f576040517f79c099f200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080518415158152602081018490526001600160a01b038616917fe3d07a93ea2012896555861271ce9e1e6a9b8e731bff56b1baa4a823317a06be91015b60405180910390a250505050565b6002546001600160a01b031633146145ac57600254604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6145b46154dc565b620f424081116145fc576040517f83f227e9000000000000000000000000000000000000000000000000000000008152620f42406004820152602481018290526044016110b1565b600c8190556040518181527f629b53ebf66271b592438aa954e367dad37de9cd1c1a2b9dc4acade7e1ff9f4090602001611358565b6001600160a01b0382811660009081526011602052604090206001810154909116331480159061466c57506002546001600160a01b03163314155b156146a1576001810154604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6203f4808211156146ea576040517f83f227e90000000000000000000000000000000000000000000000000000000081526203f4806004820152602481018390526044016110b1565b600581018290556040518281526001600160a01b038416907fda21fe7cd8964fd0f9eda8f774bfbc66c4d534811de3b80cef219e9df79a6e01906020016119ce565b6003546001600160a01b0316331461476c57600354604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6147746154dc565b6001600160a01b038116600090815260116020526040812090600682015460ff1660058111156147a6576147a6615869565b146147dd576040517f4813c5bf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600201546000036148375780600401544211614832576004818101546040517f52be750b000000000000000000000000000000000000000000000000000000008152918201524260248201526044016110b1565b61488f565b8060050154816004015461484b9190615b52565b421161488f576004818101546040517f52be750b000000000000000000000000000000000000000000000000000000008152918201524260248201526044016110b1565b6006810180546004919060ff19166001836124a9565b6001600160a01b03811660009081526011602052604081206001612258565b6148cc6154dc565b6001600160a01b03838116600090815260116020526040902060018101549091163314614923576001810154604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b428160040154111561496d576004818101546040517f9d9d3b07000000000000000000000000000000000000000000000000000000008152918201524260248201526044016110b1565b6000600682015460ff16600581111561498857614988615869565b146149bf576040517f1da42b2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001816002015410156149fe576040517f1f2a200500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60068101805460ff1916600117905560005460028201546040517fa9059cbb0000000000000000000000000000000000000000000000000000000081526001600160a01b0387811660048301526024820192909252610100909204169063a9059cbb906044016020604051808303816000875af1158015614a83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614aa79190615b06565b504661a4b103614b405760028101546040517fe325573100000000000000000000000000000000000000000000000000000000815284151560048201526024810184905260448101919091526001600160a01b0385169063e32557319034906064016000604051808303818588803b158015614b2257600080fd5b505af1158015614b36573d6000803e3d6000fd5b5050505050614be2565b46600a03614be257836001600160a01b031663350245c26040518163ffffffff1660e01b81526004016020604051808303816000875af1158015614b88573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614bac9190615b06565b614be2576040517f79c099f200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080518415158152602081018490526001600160a01b038616917fbcee3379d56c5ea65c6957af10c3ecf663f19c42892076899323d08f024d2f45910161455e565b6002546001600160a01b03163314614c6557600254604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6001600160a01b038116614ca5576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517fc714d22a2f08b695f81e7c707058db484aa5b4d6b4c9fd64beb10fe85832f60890600090a250565b6002546001600160a01b03163314614d4757600254604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b614d4f6154dc565b600a8190556040518181527f0a29121cfa398b9e95ff515ed08281dc10b2522292fa7f18606cfaaa570ba4e990602001611358565b6002546001600160a01b03163314614dc457600254604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b614dcc6154dc565b610384811015614e13576040517f52be750b0000000000000000000000000000000000000000000000000000000081526103846004820152602481018290526044016110b1565b600e8190556040518181527f4f77c2c6810f043504ce09face8a21f7648e7ba1b991530f1580f1c4ddd102e890602001611358565b614e506154dc565b6001600160a01b03808216600090815260116020526040902060018101549091163314614ea7576001810154604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6000600682015460ff166005811115614ec257614ec2615869565b14614ef9576040517f1da42b2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600181600201541015614f38576040517f1f2a200500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600401544210614f75576040517ff9202d0b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b4260048201556040516001600160a01b038316907f351eaef6165bbd44916fe1e48715217d89ad4b425db112ea45c908be6446e43c90600090a25050565b614fbb6154dc565b4661a4b114615000576040517f9fba672f00000000000000000000000000000000000000000000000000000000815261a4b160048201524660248201526044016110b1565b6001600160a01b0381811660009081526011602052604090206001810154909116331480159061503b57506003546001600160a01b03163314155b15615070576001810154604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b6002600682015460ff16600581111561508b5761508b615869565b146150c2576040517f1ba1720400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000806000846001600160a01b0316631fee5ccd6040518163ffffffff1660e01b81526004016060604051808303816000875af1158015615107573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061512b9190615f79565b60038701839055600687018054939650919450925060059160ff1916600183021790555060018401546001600160a01b039081166000908152601260209081526040808320805460ff191690559288168083526014825283832086905560158252918390208490558251868152908101859052918201839052907fe095746fb00b01d8b1f81c3f937f649fbd6ba123c09517dffe2167472021ea5c9060600160405180910390a25050505050565b6151e16154dc565b6001600160a01b0383811660009081526011602052604090206001810154909116331480159061521c57506003546001600160a01b03163314155b15615251576001810154604051630150a30b60e21b81526001600160a01b0390911660048201523360248201526044016110b1565b811561534f576001600682015460ff16600581111561527257615272615869565b146152a9576040517f1da42b2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60068101805460ff191690556040517ff88d20470000000000000000000000000000000000000000000000000000000081526004810184905282151560248201526000906001600160a01b0386169063f88d2047906044016020604051808303816000875af1158015615320573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906153449190615aed565b60028301555061548c565b6001600682015460ff16600581111561536a5761536a615869565b1415801561539157506002600682015460ff16600581111561538e5761538e615869565b14155b156153c8576040517f974da2dc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60068101805460ff199081166001908117909255818301546001600160a01b0390811660009081526012602052604090819020805490931690931790915590517ff88d20470000000000000000000000000000000000000000000000000000000081526004810185905283151560248201529085169063f88d2047906044016020604051808303816000875af1158015615466573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061548a9190615aed565b505b6002810154604080518581528415156020820152908101919091526001600160a01b038516907f610fd83131a01a963438707dc05328b654bad7cab052f0d9625cacefb54000a59060600161455e565b60005460ff16156122d5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a207061757365640000000000000000000000000000000060448201526064016110b1565b60005460ff166122d5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f742070617573656400000000000000000000000060448201526064016110b1565b6155bd615549565b6000805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b60006040517f3d602d80600a3d3981f3363d3d373d3d3d363d7300000000000000000000000081528260601b60148201527f5af43d82803e903d91602b57fd5bf3000000000000000000000000000000000060288201526037816000f09150506001600160a01b0381166156d7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f455243313136373a20637265617465206661696c65640000000000000000000060448201526064016110b1565b919050565b6156e46154dc565b6000805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586155ea3390565b6001600160a01b038116811461572e57600080fd5b50565b60008060006060848603121561574657600080fd5b833561575181615719565b9250602084013561576181615719565b929592945050506040919091013590565b60006020828403121561578457600080fd5b5035919050565b60006020828403121561579d57600080fd5b81356157a881615719565b9392505050565b600080604083850312156157c257600080fd5b82356157cd81615719565b946020939093013593505050565b801515811461572e57600080fd5b600080600080600060a0868803121561580157600080fd5b853561580c81615719565b9450602086013561581c816157db565b93506040860135925060608601359150608086013561583a816157db565b809150509295509295909350565b60006020828403121561585a57600080fd5b8135600681106157a857600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600681106158cf577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b6020810161367e8284615898565b600060e0828403121561227f57600080fd5b6000806040838503121561590657600080fd5b823561591181615719565b9150602083013561592181615719565b809150509250929050565b6001600160a01b0388811682528716602082015260408101869052606081018590526080810184905260a0810183905260e0810161596d60c0830184615898565b98975050505050505050565b6000806040838503121561598c57600080fd5b823561599781615719565b91506020830135615921816157db565b60008060008060008060c087890312156159c057600080fd5b86356159cb81615719565b955060208701356159db816157db565b945060408701356159eb816157db565b9350606087013592506080870135915060a0870135615a09816157db565b809150509295509295509295565b600080600080600060a08688031215615a2f57600080fd5b8535615a3a81615719565b94506020860135615a4a81615719565b93506040860135615a5a816157db565b92506060860135615a6a81615719565b949793965091946080013592915050565b600080600060608486031215615a9057600080fd5b8335615a9b81615719565b92506020840135615761816157db565b600080600060608486031215615ac057600080fd5b8335615acb81615719565b9250602084013591506040840135615ae2816157db565b809150509250925092565b600060208284031215615aff57600080fd5b5051919050565b600060208284031215615b1857600080fd5b81516157a8816157db565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008219821115615b6557615b65615b23565b500190565b6000808312837f800000000000000000000000000000000000000000000000000000000000000001831281151615615ba457615ba4615b23565b837f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff018313811615615bd857615bd8615b23565b50500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715615c5457615c54615bde565b604052919050565b600060e08284031215615c6e57600080fd5b60405160e0810181811067ffffffffffffffff82111715615c9157615c91615bde565b6040528251615c9f81615719565b81526020830151615caf816157db565b8060208301525060408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c08201528091505092915050565b60006020808385031215615d0557600080fd5b825167ffffffffffffffff80821115615d1d57600080fd5b818501915085601f830112615d3157600080fd5b815181811115615d4357615d43615bde565b8060051b9150615d54848301615c0d565b8181529183018401918481019088841115615d6e57600080fd5b938501935b8385101561596d5784519250615d8883615719565b8282529385019390850190615d73565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600080600080600080600080610100898b031215615de457600080fd5b885197506020890151965060408901519550606089015194506080890151935060a0890151925060c0890151615e19816157db565b8092505060e089015190509295985092959890939650565b600060208284031215615e4357600080fd5b81356157a8816157db565b61016081018635615e5e81615719565b6001600160a01b031682526020870135615e77816157db565b80151560208401525060408701356040830152606087013560608301526080870135608083015260a087013560a083015260c087013560c0830152615ec760e08301876001600160a01b03169052565b6001600160a01b0385166101008301526001600160a01b0384166101208301526001600160a01b0383166101408301529695505050505050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615615f3957615f39615b23565b500290565b600082615f74577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b600080600060608486031215615f8e57600080fd5b835192506020840151915060408401519050925092509256fea264697066735822122052b9a8682a6e67e8d07e383c283240df048d8e32f72687e0e88153dafcdd466264736f6c634300080f0033

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

000000000000000000000000bac2e501d529160ba06fc2092c94e010d56d42c200000000000000000000000031eea3a0cbd74463071a1211f83ec535c67d3212000000000000000000000000000000000000000000000000000000000bebc2000000000000000000000000000000000000000000000000000000000001312d000000000000000000000000000000000000000000000000000000000002faf0800000000000000000000000000000000000000000000000000000000000989680000000000000000000000000ff970a61a04b1ca14834a43f5de4533ebddb5cc800000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab10000000000000000000000004df53b363850b1bb33e34b6dfebeb519b3e57641000000000000000000000000295d70125e0c6437a3915fe7a6ac7205bacc2e91

-----Decoded View---------------
Arg [0] : _reader (address): 0xbAc2E501d529160Ba06Fc2092c94e010d56D42C2
Arg [1] : _stfxImplementation (address): 0x31EEA3A0CBD74463071A1211F83Ec535c67d3212
Arg [2] : _capacityPerStf (uint256): 200000000
Arg [3] : _minInvestmentAmount (uint256): 20000000
Arg [4] : _maxInvestmentAmount (uint256): 50000000
Arg [5] : _maxLeverage (uint256): 10000000
Arg [6] : _usdc (address): 0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8
Arg [7] : _weth (address): 0x82aF49447D8a07e3bd95BD0d56f35241523fBab1
Arg [8] : _admin (address): 0x4df53b363850b1Bb33E34B6dFebeB519B3E57641
Arg [9] : _treasury (address): 0x295d70125E0c6437A3915Fe7A6ac7205Bacc2e91

-----Encoded View---------------
10 Constructor Arguments found :
Arg [0] : 000000000000000000000000bac2e501d529160ba06fc2092c94e010d56d42c2
Arg [1] : 00000000000000000000000031eea3a0cbd74463071a1211f83ec535c67d3212
Arg [2] : 000000000000000000000000000000000000000000000000000000000bebc200
Arg [3] : 0000000000000000000000000000000000000000000000000000000001312d00
Arg [4] : 0000000000000000000000000000000000000000000000000000000002faf080
Arg [5] : 0000000000000000000000000000000000000000000000000000000000989680
Arg [6] : 000000000000000000000000ff970a61a04b1ca14834a43f5de4533ebddb5cc8
Arg [7] : 00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1
Arg [8] : 0000000000000000000000004df53b363850b1bb33e34b6dfebeb519b3e57641
Arg [9] : 000000000000000000000000295d70125e0c6437a3915fe7a6ac7205bacc2e91


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.