ETH Price: $3,266.06 (-4.23%)
Gas: 16 Gwei

Contract

0x6E536adDB53d1b47d357cdca83BCF460194A395F
 
Transaction Hash
Method
Block
From
To
Value
Deposit USDC201690252024-06-25 13:34:358 days ago1719322475IN
0x6E536adD...0194A395F
0 ETH0.001365426.92906469
Queue Crab For W...201397902024-06-21 11:26:3512 days ago1718969195IN
0x6E536adD...0194A395F
0 ETH0.000967155.41425415
Deposit USDC201355882024-06-20 21:22:2312 days ago1718918543IN
0x6E536adD...0194A395F
0 ETH0.001164565.90974478
Deposit USDC200898762024-06-14 11:54:2319 days ago1718366063IN
0x6E536adD...0194A395F
0 ETH0.001333626.93620833
Deposit USDC200784182024-06-12 21:25:2320 days ago1718227523IN
0x6E536adD...0194A395F
0 ETH0.0025933913.48827299
Deposit USDC200780612024-06-12 20:13:4720 days ago1718223227IN
0x6E536adD...0194A395F
0 ETH0.0037088221.7677121
Queue Crab For W...200644682024-06-10 22:39:4722 days ago1718059187IN
0x6E536adD...0194A395F
0 ETH0.0019414610.58415167
Deposit USDC200614732024-06-10 12:36:4723 days ago1718023007IN
0x6E536adD...0194A395F
0 ETH0.001312447.00085258
Queue Crab For W...199923072024-05-31 20:50:1132 days ago1717188611IN
0x6E536adD...0194A395F
0 ETH0.001502238.18962005
Queue Crab For W...199461582024-05-25 10:00:3539 days ago1716631235IN
0x6E536adD...0194A395F
0 ETH0.000689183.85817346
Queue Crab For W...199238332024-05-22 7:07:5942 days ago1716361679IN
0x6E536adD...0194A395F
0 ETH0.001330748
Queue Crab For W...199159762024-05-21 4:44:3543 days ago1716266675IN
0x6E536adD...0194A395F
0 ETH0.001547548.66338767
Withdraw USDC199151972024-05-21 2:07:4743 days ago1716257267IN
0x6E536adD...0194A395F
0 ETH0.0008879112.5
Withdraw USDC199133402024-05-20 19:53:4744 days ago1716234827IN
0x6E536adD...0194A395F
0 ETH0.0093590688
Deposit USDC199095882024-05-20 7:16:2344 days ago1716189383IN
0x6E536adD...0194A395F
0 ETH0.000523592.6570474
Deposit USDC198900042024-05-17 13:31:2347 days ago1715952683IN
0x6E536adD...0194A395F
0 ETH0.001401368
Deposit USDC198544872024-05-12 14:18:4752 days ago1715523527IN
0x6E536adD...0194A395F
0 ETH0.001172166.0964343
Queue Crab For W...198409062024-05-10 16:43:5954 days ago1715359439IN
0x6E536adD...0194A395F
0 ETH0.000197956.60105527
Queue Crab For W...198409032024-05-10 16:43:2354 days ago1715359403IN
0x6E536adD...0194A395F
0 ETH0.000182956.1010021
Queue Crab For W...198409002024-05-10 16:42:4754 days ago1715359367IN
0x6E536adD...0194A395F
0 ETH0.000192946.43400299
Queue Crab For W...198377692024-05-10 6:12:5954 days ago1715321579IN
0x6E536adD...0194A395F
0 ETH0.000879624.92424092
Withdraw USDC198315552024-05-09 9:21:2355 days ago1715246483IN
0x6E536adD...0194A395F
0 ETH0.000423615
Queue Crab For W...198302842024-05-09 5:05:2355 days ago1715231123IN
0x6E536adD...0194A395F
0 ETH0.00087194.75332393
Deposit USDC198239992024-05-08 7:57:4756 days ago1715155067IN
0x6E536adD...0194A395F
0 ETH0.001063986.24468208
Deposit USDC198225222024-05-08 3:00:1156 days ago1715137211IN
0x6E536adD...0194A395F
0 ETH0.001119665.97247748
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To Value
201699572024-06-25 16:41:238 days ago1719333683
0x6E536adD...0194A395F
1.69251296 ETH
201699572024-06-25 16:41:238 days ago1719333683
0x6E536adD...0194A395F
1.69251296 ETH
201198962024-06-18 16:41:3515 days ago1718728895
0x6E536adD...0194A395F
0.01597584 ETH
201198962024-06-18 16:41:3515 days ago1718728895
0x6E536adD...0194A395F
10.62373864 ETH
201198962024-06-18 16:41:3515 days ago1718728895
0x6E536adD...0194A395F
10.63971449 ETH
200699602024-06-11 17:04:3522 days ago1718125475
0x6E536adD...0194A395F
11.42143778 ETH
200699602024-06-11 17:04:3522 days ago1718125475
0x6E536adD...0194A395F
11.42143778 ETH
200198592024-06-04 17:10:1129 days ago1717521011
0x6E536adD...0194A395F
3.01637135 ETH
200198592024-06-04 17:10:1129 days ago1717521011
0x6E536adD...0194A395F
3.01637135 ETH
199696422024-05-28 16:45:1136 days ago1716914711
0x6E536adD...0194A395F
168.23481991 ETH
199696422024-05-28 16:45:1136 days ago1716914711
0x6E536adD...0194A395F
168.23481991 ETH
199195342024-05-21 16:40:3543 days ago1716309635
0x6E536adD...0194A395F
6.30582675 ETH
199195342024-05-21 16:40:3543 days ago1716309635
0x6E536adD...0194A395F
6.30582675 ETH
198694862024-05-14 16:41:5950 days ago1715704919
0x6E536adD...0194A395F
0.01416946 ETH
198694862024-05-14 16:41:5950 days ago1715704919
0x6E536adD...0194A395F
5.17927946 ETH
198694862024-05-14 16:41:5950 days ago1715704919
0x6E536adD...0194A395F
5.19344892 ETH
198194642024-05-07 16:45:1157 days ago1715100311
0x6E536adD...0194A395F
0.68167211 ETH
198194642024-05-07 16:45:1157 days ago1715100311
0x6E536adD...0194A395F
308.96757038 ETH
198194642024-05-07 16:45:1157 days ago1715100311
0x6E536adD...0194A395F
309.64924249 ETH
197693902024-04-30 16:42:4764 days ago1714495367
0x6E536adD...0194A395F
0.00863087 ETH
197693902024-04-30 16:42:4764 days ago1714495367
0x6E536adD...0194A395F
0.00863087 ETH
197693902024-04-30 16:42:4764 days ago1714495367
0x6E536adD...0194A395F
0.0210513 ETH
197693902024-04-30 16:42:4764 days ago1714495367
0x6E536adD...0194A395F
6.41177982 ETH
197693902024-04-30 16:42:4764 days ago1714495367
0x6E536adD...0194A395F
6.43283113 ETH
197193522024-04-23 16:41:5971 days ago1713890519
0x6E536adD...0194A395F
0.00075407 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
CrabNetting

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 16 : CrabNetting.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.13;

// interface
import {IERC20} from "openzeppelin/token/ERC20/IERC20.sol";
import {IWETH} from "../src/interfaces/IWETH.sol";
import {IOracle} from "../src/interfaces/IOracle.sol";
import "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol";
import {ICrabStrategyV2} from "../src/interfaces/ICrabStrategyV2.sol";
import {IController} from "../src/interfaces/IController.sol";

// contract
import {Ownable} from "openzeppelin/access/Ownable.sol";
import {EIP712} from "openzeppelin/utils/cryptography/draft-EIP712.sol";
import {ECDSA} from "openzeppelin/utils/cryptography/ECDSA.sol";

/// @dev order struct for a signed order from market maker
struct Order {
    uint256 bidId;
    address trader;
    uint256 quantity;
    uint256 price;
    bool isBuying;
    uint256 expiry;
    uint256 nonce;
    uint8 v;
    bytes32 r;
    bytes32 s;
}

/// @dev struct to store proportional amounts of erc20s (received or to send)
struct Portion {
    uint256 crab;
    uint256 eth;
    uint256 sqth;
}

/// @dev params for deposit auction
struct DepositAuctionParams {
    /// @dev USDC to deposit
    uint256 depositsQueued;
    /// @dev minETH equivalent to get from uniswap of the USDC to deposit
    uint256 minEth;
    /// @dev total ETH to deposit after selling the minted SQTH
    uint256 totalDeposit;
    /// @dev orders to buy sqth
    Order[] orders;
    /// @dev price from the auction to sell sqth
    uint256 clearingPrice;
    /// @dev remaining ETH to flashDeposit
    uint256 ethToFlashDeposit;
    /// @dev fee to pay uniswap for ethUSD swap
    uint24 ethUSDFee;
    /// @dev fee to pay uniswap for sqthETH swap
    uint24 flashDepositFee;
}

/// @dev params for withdraw auction
struct WithdrawAuctionParams {
    /// @dev amont of crab to queue for withdrawal
    uint256 crabToWithdraw;
    /// @dev orders that sell sqth to the auction
    Order[] orders;
    /// @dev price that the auction pays for the purchased sqth
    uint256 clearingPrice;
    /// @dev minUSDC to receive from swapping the ETH obtained by withdrawing
    uint256 minUSDC;
    /// @dev uniswap fee for swapping eth to USD;
    uint24 ethUSDFee;
}

/// @dev receipt used to store deposits and withdraws
struct Receipt {
    /// @dev address of the depositor or withdrawer
    address sender;
    /// @dev usdc amount to queue for deposit or crab amount to queue for withdrawal
    uint256 amount;
    /// @dev time of deposit
    uint256 timestamp;
}

/**
 * Crab netting error codes
 * N1: deposit amount smaller than minimum OTC amount
 * N2: auction is live
 * N3: remaining amount smaller than minimum, consider removing full balance
 * N4: force withdraw after 1 week from deposit
 * N5: withdraw amount smaller than minimum OTC amount
 * N6: remaining amount smaller than minimum, consider removing full balance
 * N7: Not enough deposits to net
 * N8: Not enough withdrawals to net
 * N9: signature incorrect
 * N10: order expired
 * N11: Min ETH out too low
 * N12: auction order not buying sqth
 * N13: buy order price less than clearing
 * N14: not enough buy orders for sqth
 * N15: auction order is not selling
 * N16: sell order price greater than clearing
 * N17: min USDC out too low
 * N18: twap period cannot be less than 180
 * N19: Price tolerance has to be less than 20%
 * N20: Nonce already used
 * N21: Price too high relative to Uniswap twap.
 * N22: Price too low relative to Uniswap twap.
 * N23: Crab Price too high
 * N24: Crab Price too low
 * N25: only weth and crab can send me monies
 */

/**
 * @dev CrabNetting contract
 * @notice Contract for Netting Deposits and Withdrawals
 * @author Opyn team
 */
contract CrabNetting is Ownable, EIP712 {
    /// @dev typehash for signed orders
    bytes32 private constant _CRAB_NETTING_TYPEHASH = keccak256(
        "Order(uint256 bidId,address trader,uint256 quantity,uint256 price,bool isBuying,uint256 expiry,uint256 nonce)"
    );
    /// @dev owner sets to true when starting auction
    bool public isAuctionLive;

    /// @dev sqth twap period
    uint32 public immutable sqthTwapPeriod;
    /// @dev twap period to use for auction calculations
    uint32 public auctionTwapPeriod = 420 seconds;

    /// @dev min USDC amounts to withdraw or deposit via netting
    uint256 public minUSDCAmount;

    /// @dev min CRAB amounts to withdraw or deposit via netting
    uint256 public minCrabAmount;

    // @dev OTC price must be within this distance of the uniswap twap price
    uint256 public otcPriceTolerance = 5e16; // 5%
    // @dev OTC price tolerance cannot exceed 20%
    uint256 public constant MAX_OTC_PRICE_TOLERANCE = 2e17; // 20%

    /// @dev address for ERC20 tokens
    address public immutable usdc;
    address public immutable crab;
    address public immutable weth;
    address public immutable sqth;

    /// @dev address for uniswap router
    ISwapRouter public immutable swapRouter;

    /// @dev address for uniswap oracle
    address public immutable oracle;

    /// @dev address for sqth eth pool
    address public immutable ethSqueethPool;

    /// @dev address for usdc eth pool
    address public immutable ethUsdcPool;

    /// @dev address for sqth controller
    address public immutable sqthController;

    /// @dev array index of last processed deposits
    uint256 public depositsIndex;

    /// @dev array index of last processed withdraws
    uint256 public withdrawsIndex;

    /// @dev array of deposit receipts
    Receipt[] public deposits;
    /// @dev array of withdrawal receipts
    Receipt[] public withdraws;

    /// @dev usd amount to deposit for an address
    mapping(address => uint256) public usdBalance;

    /// @dev crab amount to withdraw for an address
    mapping(address => uint256) public crabBalance;

    /// @dev indexes of deposit receipts of an address
    mapping(address => uint256[]) public userDepositsIndex;

    /// @dev indexes of withdraw receipts of an address
    mapping(address => uint256[]) public userWithdrawsIndex;

    /// @dev store the used flag for a nonce for each address
    mapping(address => mapping(uint256 => bool)) public nonces;

    event USDCQueued(
        address indexed depositor, uint256 amount, uint256 depositorsBalance, uint256 indexed receiptIndex
    );

    event USDCDeQueued(address indexed depositor, uint256 amount, uint256 depositorsBalance);

    event CrabQueued(
        address indexed withdrawer, uint256 amount, uint256 withdrawersBalance, uint256 indexed receiptIndex
    );

    event CrabDeQueued(address indexed withdrawer, uint256 amount, uint256 withdrawersBalance);

    event USDCDeposited(
        address indexed depositor,
        uint256 usdcAmount,
        uint256 crabAmount,
        uint256 indexed receiptIndex,
        uint256 refundedETH
    );

    event CrabWithdrawn(
        address indexed withdrawer, uint256 crabAmount, uint256 usdcAmount, uint256 indexed receiptIndex
    );

    event WithdrawRejected(address indexed withdrawer, uint256 crabAmount, uint256 index);

    event BidTraded(uint256 indexed bidId, address indexed trader, uint256 quantity, uint256 price, bool isBuying);

    event SetAuctionTwapPeriod(uint32 previousTwap, uint32 newTwap);
    event SetOTCPriceTolerance(uint256 previousTolerance, uint256 newOtcPriceTolerance);
    event SetMinCrab(uint256 amount);
    event SetMinUSDC(uint256 amount);
    event SetDepositsIndex(uint256 newDepositsIndex);
    event SetWithdrawsIndex(uint256 newWithdrawsIndex);
    event NonceTrue(address sender, uint256 nonce);
    event ToggledAuctionLive(bool isAuctionLive);

    /**
     * @notice netting contract constructor
     * @dev initializes the erc20 address, uniswap router and approves them
     * @param _crab address of crab contract token
     * @param _swapRouter address of uniswap swap router
     */
    constructor(address _crab, address _swapRouter) EIP712("CRABNetting", "1") {
        crab = _crab;
        swapRouter = ISwapRouter(_swapRouter);

        sqthController = ICrabStrategyV2(_crab).powerTokenController();
        usdc = IController(sqthController).quoteCurrency();
        weth = ICrabStrategyV2(_crab).weth();
        sqth = ICrabStrategyV2(_crab).wPowerPerp();
        oracle = ICrabStrategyV2(_crab).oracle();
        ethSqueethPool = ICrabStrategyV2(_crab).ethWSqueethPool();
        ethUsdcPool = IController(sqthController).ethQuoteCurrencyPool();
        sqthTwapPeriod = IController(sqthController).TWAP_PERIOD();

        // approve crab and sqth so withdraw can happen
        IERC20(sqth).approve(crab, type(uint256).max);

        IERC20(weth).approve(address(swapRouter), type(uint256).max);
        IERC20(usdc).approve(address(swapRouter), type(uint256).max);
    }

    /**
     * @dev view function to get the domain seperator used in signing
     */
    function DOMAIN_SEPARATOR() external view returns (bytes32) {
        return _domainSeparatorV4();
    }

    /**
     * @dev toggles the value of isAuctionLive
     */
    function toggleAuctionLive() external onlyOwner {
        isAuctionLive = !isAuctionLive;
        emit ToggledAuctionLive(isAuctionLive);
    }

    /**
     * @notice set nonce to true
     * @param _nonce the number to be set true
     */
    function setNonceTrue(uint256 _nonce) external {
        nonces[msg.sender][_nonce] = true;
        emit NonceTrue(msg.sender, _nonce);
    }

    /**
     * @notice set minUSDCAmount
     * @param _amount the number to be set as minUSDC
     */
    function setMinUSDC(uint256 _amount) external onlyOwner {
        minUSDCAmount = _amount;
        emit SetMinUSDC(_amount);
    }

    /**
     * @notice set minCrabAmount
     * @param _amount the number to be set as minCrab
     */
    function setMinCrab(uint256 _amount) external onlyOwner {
        minCrabAmount = _amount;
        emit SetMinCrab(_amount);
    }

    /**
     * @notice set the depositIndex so that we want to skip processing some deposits
     * @param _newDepositsIndex the new deposits index
     */
    function setDepositsIndex(uint256 _newDepositsIndex) external onlyOwner {
        depositsIndex = _newDepositsIndex;
        emit SetDepositsIndex(_newDepositsIndex);
    }

    /**
     * @notice set the withdraw index so that we want to skip processing some withdraws
     * @param _newWithdrawsIndex the new withdraw index
     */
    function setWithdrawsIndex(uint256 _newWithdrawsIndex) external onlyOwner {
        withdrawsIndex = _newWithdrawsIndex;
        emit SetWithdrawsIndex(_newWithdrawsIndex);
    }

    /**
     * @notice queue USDC for deposit into crab strategy
     * @param _amount USDC amount to deposit
     */
    function depositUSDC(uint256 _amount) external {
        require(_amount >= minUSDCAmount, "N1");

        IERC20(usdc).transferFrom(msg.sender, address(this), _amount);

        // update usd balance of user, add their receipt, and receipt index to user deposits index
        usdBalance[msg.sender] = usdBalance[msg.sender] + _amount;
        deposits.push(Receipt(msg.sender, _amount, block.timestamp));
        userDepositsIndex[msg.sender].push(deposits.length - 1);

        emit USDCQueued(msg.sender, _amount, usdBalance[msg.sender], deposits.length - 1);
    }

    /**
     * @notice withdraw USDC from queue
     * @param _amount USDC amount to dequeue
     * @param _force forceWithdraw if deposited more than a week ago
     */
    function withdrawUSDC(uint256 _amount, bool _force) external {
        require(!isAuctionLive || _force, "N2");

        usdBalance[msg.sender] = usdBalance[msg.sender] - _amount;
        require(usdBalance[msg.sender] >= minUSDCAmount || usdBalance[msg.sender] == 0, "N3");

        // start withdrawing from the users last deposit
        uint256 toRemove = _amount;
        uint256 lastIndexP1 = userDepositsIndex[msg.sender].length;
        for (uint256 i = lastIndexP1; i > 0; i--) {
            Receipt storage r = deposits[userDepositsIndex[msg.sender][i - 1]];
            if (_force) {
                require(block.timestamp > r.timestamp + 1 weeks, "N4");
            }
            if (r.amount > toRemove) {
                r.amount -= toRemove;
                toRemove = 0;
                break;
            } else {
                toRemove -= r.amount;
                delete deposits[userDepositsIndex[msg.sender][i - 1]];
                userDepositsIndex[msg.sender].pop();
            }
        }
        IERC20(usdc).transfer(msg.sender, _amount);

        emit USDCDeQueued(msg.sender, _amount, usdBalance[msg.sender]);
    }

    /**
     * @notice queue Crab for withdraw from crab strategy
     * @param _amount crab amount to withdraw
     */
    function queueCrabForWithdrawal(uint256 _amount) external {
        require(_amount >= minCrabAmount, "N5");
        IERC20(crab).transferFrom(msg.sender, address(this), _amount);
        crabBalance[msg.sender] = crabBalance[msg.sender] + _amount;
        withdraws.push(Receipt(msg.sender, _amount, block.timestamp));
        userWithdrawsIndex[msg.sender].push(withdraws.length - 1);
        emit CrabQueued(msg.sender, _amount, crabBalance[msg.sender], withdraws.length - 1);
    }

    /**
     * @notice withdraw Crab from queue
     * @param _amount Crab amount to dequeue
     * @param _force forceWithdraw if deposited more than a week ago
     */
    function dequeueCrab(uint256 _amount, bool _force) external {
        require(!isAuctionLive || _force, "N2");
        crabBalance[msg.sender] = crabBalance[msg.sender] - _amount;
        require(crabBalance[msg.sender] >= minCrabAmount || crabBalance[msg.sender] == 0, "N6");
        // deQueue crab from the last, last in first out
        uint256 toRemove = _amount;
        uint256 lastIndexP1 = userWithdrawsIndex[msg.sender].length;
        for (uint256 i = lastIndexP1; i > 0; i--) {
            Receipt storage r = withdraws[userWithdrawsIndex[msg.sender][i - 1]];
            if (_force) {
                require(block.timestamp > r.timestamp + 1 weeks, "N4");
            }
            if (r.amount > toRemove) {
                r.amount -= toRemove;
                toRemove = 0;
                break;
            } else {
                toRemove -= r.amount;
                delete withdraws[userWithdrawsIndex[msg.sender][i - 1]];
                userWithdrawsIndex[msg.sender].pop();
            }
        }
        IERC20(crab).transfer(msg.sender, _amount);
        emit CrabDeQueued(msg.sender, _amount, crabBalance[msg.sender]);
    }

    /**
     * @dev swaps _quantity amount of usdc for crab at _price
     * @param _price price of crab in usdc
     * @param _quantity amount of USDC to net
     */
    function netAtPrice(uint256 _price, uint256 _quantity) external onlyOwner {
        _checkCrabPrice(_price);
        uint256 crabQuantity = (_quantity * 1e18) / _price;
        require(_quantity <= IERC20(usdc).balanceOf(address(this)), "N7");
        require(crabQuantity <= IERC20(crab).balanceOf(address(this)), "N8");

        // process deposits and send crab
        uint256 i = depositsIndex;
        uint256 amountToSend;
        while (_quantity > 0) {
            Receipt memory deposit = deposits[i];
            if (deposit.amount == 0) {
                i++;
                continue;
            }
            if (deposit.amount <= _quantity) {
                // deposit amount is lesser than quantity use it fully
                _quantity = _quantity - deposit.amount;
                usdBalance[deposit.sender] -= deposit.amount;
                amountToSend = (deposit.amount * 1e18) / _price;
                IERC20(crab).transfer(deposit.sender, amountToSend);
                emit USDCDeposited(deposit.sender, deposit.amount, amountToSend, i, 0);
                delete deposits[i];
                i++;
            } else {
                // deposit amount is greater than quantity; use it partially
                deposits[i].amount = deposit.amount - _quantity;
                usdBalance[deposit.sender] -= _quantity;
                amountToSend = (_quantity * 1e18) / _price;
                IERC20(crab).transfer(deposit.sender, amountToSend);
                emit USDCDeposited(deposit.sender, _quantity, amountToSend, i, 0);
                _quantity = 0;
            }
        }
        depositsIndex = i;

        // process withdraws and send usdc
        i = withdrawsIndex;
        while (crabQuantity > 0) {
            Receipt memory withdraw = withdraws[i];
            if (withdraw.amount == 0) {
                i++;
                continue;
            }
            if (withdraw.amount <= crabQuantity) {
                crabQuantity = crabQuantity - withdraw.amount;
                crabBalance[withdraw.sender] -= withdraw.amount;
                amountToSend = (withdraw.amount * _price) / 1e18;
                IERC20(usdc).transfer(withdraw.sender, amountToSend);

                emit CrabWithdrawn(withdraw.sender, withdraw.amount, amountToSend, i);

                delete withdraws[i];
                i++;
            } else {
                withdraws[i].amount = withdraw.amount - crabQuantity;
                crabBalance[withdraw.sender] -= crabQuantity;
                amountToSend = (crabQuantity * _price) / 1e18;
                IERC20(usdc).transfer(withdraw.sender, amountToSend);

                emit CrabWithdrawn(withdraw.sender, withdraw.amount, amountToSend, i);

                crabQuantity = 0;
            }
        }
        withdrawsIndex = i;
    }

    /**
     * @return sum usdc amount in queue
     */
    function depositsQueued() external view returns (uint256) {
        uint256 j = depositsIndex;
        uint256 sum;
        while (j < deposits.length) {
            sum = sum + deposits[j].amount;
            j++;
        }
        return sum;
    }

    /**
     * @return sum crab amount in queue
     */
    function withdrawsQueued() external view returns (uint256) {
        uint256 j = withdrawsIndex;
        uint256 sum;
        while (j < withdraws.length) {
            sum = sum + withdraws[j].amount;
            j++;
        }
        return sum;
    }

    function checkOrder(Order memory _order) external view {
        return _checkOrder(_order);
    }

    /**
     * @dev checks the expiry nonce and signer of an order
     * @param _order is the Order struct
     */
    function _checkOrder(Order memory _order) internal view {
        bytes32 structHash = keccak256(
            abi.encode(
                _CRAB_NETTING_TYPEHASH,
                _order.bidId,
                _order.trader,
                _order.quantity,
                _order.price,
                _order.isBuying,
                _order.expiry,
                _order.nonce
            )
        );

        bytes32 hash = _hashTypedDataV4(structHash);
        address offerSigner = ECDSA.recover(hash, _order.v, _order.r, _order.s);
        require(offerSigner == _order.trader, "N9");
        require(_order.expiry >= block.timestamp, "N10");
    }

    /**
     * @dev calculates wSqueeth minted when amount is deposited
     * @param _amount to deposit into crab
     */
    function _debtToMint(uint256 _amount) internal view returns (uint256) {
        uint256 feeAdjustment = _calcFeeAdjustment();
        (,, uint256 collateral, uint256 debt) = ICrabStrategyV2(crab).getVaultDetails();
        uint256 wSqueethToMint = (_amount * debt) / (collateral + (debt * feeAdjustment) / 1e18);
        return wSqueethToMint;
    }

    /**
     * @dev takes in orders from mm's to buy sqth and deposits the usd amount from the depositQueue into crab along with the eth from selling sqth
     * @param _p DepositAuction Params that contain orders, usdToDeposit, uniswap min amount and fee
     */
    function depositAuction(DepositAuctionParams calldata _p) external onlyOwner {
        _checkOTCPrice(_p.clearingPrice, false);
        uint256 ethUSDCPrice = IOracle(oracle).getTwap(ethUsdcPool, weth, usdc, auctionTwapPeriod, true);
        require((_p.depositsQueued * (1e18 - otcPriceTolerance) * 1e12 / ethUSDCPrice) < _p.minEth, "N11");
        /**
         * step 1: get eth from mm
         *     step 2: get eth from deposit usdc
         *     step 3: crab deposit
         *     step 4: flash deposit
         *     step 5: send sqth to mms
         *     step 6: send crab to depositors
         */
        uint256 initCrabBalance = IERC20(crab).balanceOf(address(this));
        uint256 initEthBalance = address(this).balance;

        uint256 sqthToSell = _debtToMint(_p.totalDeposit);
        // step 1 get all the eth in
        uint256 remainingToSell = sqthToSell;
        for (uint256 i = 0; i < _p.orders.length; i++) {
            require(_p.orders[i].isBuying, "N12");
            require(_p.orders[i].price >= _p.clearingPrice, "N13");
            _checkOrder(_p.orders[i]);
            _useNonce(_p.orders[i].trader, _p.orders[i].nonce);
            if (_p.orders[i].quantity >= remainingToSell) {
                IWETH(weth).transferFrom(
                    _p.orders[i].trader, address(this), (remainingToSell * _p.clearingPrice) / 1e18
                );
                remainingToSell = 0;
                break;
            } else {
                IWETH(weth).transferFrom(
                    _p.orders[i].trader, address(this), (_p.orders[i].quantity * _p.clearingPrice) / 1e18
                );
                remainingToSell -= _p.orders[i].quantity;
            }
        }
        require(remainingToSell == 0, "N14");

        // step 2
        ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({
            tokenIn: usdc,
            tokenOut: weth,
            fee: _p.ethUSDFee,
            recipient: address(this),
            deadline: block.timestamp,
            amountIn: _p.depositsQueued,
            amountOutMinimum: _p.minEth,
            sqrtPriceLimitX96: 0
        });
        swapRouter.exactInputSingle(params);

        // step 3
        IWETH(weth).withdraw(IWETH(weth).balanceOf(address(this)));
        ICrabStrategyV2(crab).deposit{value: _p.totalDeposit}();

        // step 4
        Portion memory to_send;
        to_send.eth = address(this).balance - initEthBalance;
        if (to_send.eth > 0 && _p.ethToFlashDeposit > 0) {
            if (to_send.eth <= _p.ethToFlashDeposit) {
                // we cant send more than the flashDeposit
                ICrabStrategyV2(crab).flashDeposit{value: to_send.eth}(_p.ethToFlashDeposit, _p.flashDepositFee);
            }
        }

        // step 5
        to_send.sqth = IERC20(sqth).balanceOf(address(this));
        remainingToSell = to_send.sqth;
        for (uint256 j = 0; j < _p.orders.length; j++) {
            if (_p.orders[j].quantity < remainingToSell) {
                IERC20(sqth).transfer(_p.orders[j].trader, _p.orders[j].quantity);
                remainingToSell -= _p.orders[j].quantity;
                emit BidTraded(_p.orders[j].bidId, _p.orders[j].trader, _p.orders[j].quantity, _p.clearingPrice, true);
            } else {
                IERC20(sqth).transfer(_p.orders[j].trader, remainingToSell);
                emit BidTraded(_p.orders[j].bidId, _p.orders[j].trader, remainingToSell, _p.clearingPrice, true);
                break;
            }
        }

        // step 6 send crab to depositors
        uint256 remainingDeposits = _p.depositsQueued;
        uint256 k = depositsIndex;

        to_send.crab = IERC20(crab).balanceOf(address(this)) - initCrabBalance;
        // get the balance between start and now
        to_send.eth = address(this).balance - initEthBalance;
        IWETH(weth).deposit{value: to_send.eth}();

        while (remainingDeposits > 0) {
            uint256 queuedAmount = deposits[k].amount;
            Portion memory portion;
            if (queuedAmount == 0) {
                k++;
                continue;
            }
            if (queuedAmount <= remainingDeposits) {
                remainingDeposits = remainingDeposits - queuedAmount;
                usdBalance[deposits[k].sender] -= queuedAmount;

                portion.crab = queuedAmount * to_send.crab / _p.depositsQueued;

                IERC20(crab).transfer(deposits[k].sender, portion.crab);

                portion.eth = queuedAmount * to_send.eth / _p.depositsQueued;
                if (portion.eth > 1e12) {
                    IWETH(weth).transfer(deposits[k].sender, portion.eth);
                } else {
                    portion.eth = 0;
                }
                emit USDCDeposited(deposits[k].sender, queuedAmount, portion.crab, k, portion.eth);

                delete deposits[k];
                k++;
            } else {
                usdBalance[deposits[k].sender] -= remainingDeposits;

                portion.crab = remainingDeposits * to_send.crab / _p.depositsQueued;
                IERC20(crab).transfer(deposits[k].sender, portion.crab);

                portion.eth = remainingDeposits * to_send.eth / _p.depositsQueued;
                if (portion.eth > 1e12) {
                    IWETH(weth).transfer(deposits[k].sender, portion.eth);
                } else {
                    portion.eth = 0;
                }
                emit USDCDeposited(deposits[k].sender, remainingDeposits, portion.crab, k, portion.eth);

                deposits[k].amount -= remainingDeposits;
                remainingDeposits = 0;
            }
        }
        depositsIndex = k;
        isAuctionLive = false;
    }

    /**
     * @dev takes in orders from mm's to sell sqth and withdraws the crab amount in q
     * @param _p Withdraw Params that contain orders, crabToWithdraw, uniswap min amount and fee
     */
    function withdrawAuction(WithdrawAuctionParams calldata _p) public onlyOwner {
        _checkOTCPrice(_p.clearingPrice, true);
        uint256 initWethBalance = IERC20(weth).balanceOf(address(this));
        uint256 initEthBalance = address(this).balance;
        /**
         * step 1: get sqth from mms
         *     step 2: withdraw from crab
         *     step 3: send eth to mms
         *     step 4: convert eth to usdc
         *     step 5: send usdc to withdrawers
         */

        // step 1 get sqth from mms
        uint256 sqthRequired = ICrabStrategyV2(crab).getWsqueethFromCrabAmount(_p.crabToWithdraw);
        uint256 toPull = sqthRequired;
        for (uint256 i = 0; i < _p.orders.length && toPull > 0; i++) {
            _checkOrder(_p.orders[i]);
            _useNonce(_p.orders[i].trader, _p.orders[i].nonce);
            require(!_p.orders[i].isBuying, "N15");
            require(_p.orders[i].price <= _p.clearingPrice, "N16");
            if (_p.orders[i].quantity < toPull) {
                toPull -= _p.orders[i].quantity;
                IERC20(sqth).transferFrom(_p.orders[i].trader, address(this), _p.orders[i].quantity);
            } else {
                IERC20(sqth).transferFrom(_p.orders[i].trader, address(this), toPull);
                toPull = 0;
            }
        }

        // step 2 withdraw from crab
        ICrabStrategyV2(crab).withdraw(_p.crabToWithdraw);

        // step 3 pay all mms
        IWETH(weth).deposit{value: address(this).balance - initEthBalance}();
        toPull = sqthRequired;
        uint256 sqthQuantity;
        for (uint256 i = 0; i < _p.orders.length && toPull > 0; i++) {
            if (_p.orders[i].quantity < toPull) {
                sqthQuantity = _p.orders[i].quantity;
            } else {
                sqthQuantity = toPull;
            }
            IERC20(weth).transfer(_p.orders[i].trader, (sqthQuantity * _p.clearingPrice) / 1e18);
            toPull -= sqthQuantity;
            emit BidTraded(_p.orders[i].bidId, _p.orders[i].trader, sqthQuantity, _p.clearingPrice, false);
        }

        // step 4 convert to USDC
        uint256 ethUSDCPrice = IOracle(oracle).getTwap(ethUsdcPool, weth, usdc, auctionTwapPeriod, true);
        uint256 amountIn = (IERC20(weth).balanceOf(address(this)) - initWethBalance);
        require((amountIn * ethUSDCPrice * (1e18 - otcPriceTolerance) / 1e36 / 1e12) < _p.minUSDC, "N17");
        ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({
            tokenIn: address(weth),
            tokenOut: address(usdc),
            fee: _p.ethUSDFee,
            recipient: address(this),
            deadline: block.timestamp,
            amountIn: amountIn,
            amountOutMinimum: _p.minUSDC,
            sqrtPriceLimitX96: 0
        });
        uint256 usdcReceived = swapRouter.exactInputSingle(params);

        // step 5 pay all withdrawers and mark their withdraws as done
        uint256 remainingWithdraws = _p.crabToWithdraw;
        uint256 j = withdrawsIndex;
        uint256 usdcAmount;
        while (remainingWithdraws > 0) {
            Receipt memory withdraw = withdraws[j];
            if (withdraw.amount == 0) {
                j++;
                continue;
            }
            if (withdraw.amount <= remainingWithdraws) {
                // full usage
                remainingWithdraws -= withdraw.amount;
                crabBalance[withdraw.sender] -= withdraw.amount;

                // send proportional usdc
                usdcAmount = withdraw.amount * usdcReceived / _p.crabToWithdraw;
                IERC20(usdc).transfer(withdraw.sender, usdcAmount);
                emit CrabWithdrawn(withdraw.sender, withdraw.amount, usdcAmount, j);
                delete withdraws[j];
                j++;
            } else {
                withdraws[j].amount -= remainingWithdraws;
                crabBalance[withdraw.sender] -= remainingWithdraws;

                // send proportional usdc
                usdcAmount = remainingWithdraws * usdcReceived / _p.crabToWithdraw;
                IERC20(usdc).transfer(withdraw.sender, usdcAmount);
                emit CrabWithdrawn(withdraw.sender, remainingWithdraws, usdcAmount, j);

                remainingWithdraws = 0;
            }
        }
        withdrawsIndex = j;
        isAuctionLive = false;
    }

    /**
     * @dev owner rejects the withdraw at index i thereby sending the withdrawer their crab back
     * @param i index of the Withdraw receipt to reject
     */
    function rejectWithdraw(uint256 i) external onlyOwner {
        Receipt memory withdraw = withdraws[i];
        crabBalance[withdraw.sender] -= withdraw.amount;
        ICrabStrategyV2(crab).transfer(withdraw.sender, withdraw.amount);
        delete withdraws[i];

        emit WithdrawRejected(withdraw.sender, withdraw.amount, i);
    }

    /**
     * @notice owner can set the twap period in seconds that is used for obtaining TWAP prices
     * @param _auctionTwapPeriod the twap period, in seconds
     */
    function setAuctionTwapPeriod(uint32 _auctionTwapPeriod) external onlyOwner {
        require(_auctionTwapPeriod >= 180, "N18");
        uint32 previousTwap = auctionTwapPeriod;

        auctionTwapPeriod = _auctionTwapPeriod;

        emit SetAuctionTwapPeriod(previousTwap, _auctionTwapPeriod);
    }

    /**
     * @notice owner can set a threshold, scaled by 1e18 that determines the maximum discount of a clearing sale price to the current uniswap twap price
     * @param _otcPriceTolerance the OTC price tolerance, in percent, scaled by 1e18
     */
    function setOTCPriceTolerance(uint256 _otcPriceTolerance) external onlyOwner {
        // Tolerance cannot be more than 20%
        require(_otcPriceTolerance <= MAX_OTC_PRICE_TOLERANCE, "N19");
        uint256 previousOtcTolerance = otcPriceTolerance;

        otcPriceTolerance = _otcPriceTolerance;

        emit SetOTCPriceTolerance(previousOtcTolerance, _otcPriceTolerance);
    }

    /**
     * @dev set nonce flag of the trader to true
     * @param _trader address of the signer
     * @param _nonce number that is to be traded only once
     */
    function _useNonce(address _trader, uint256 _nonce) internal {
        require(!nonces[_trader][_nonce], "N20");
        nonces[_trader][_nonce] = true;
    }

    /**
     * @notice check that the proposed sale price is within a tolerance of the current Uniswap twap
     * @param _price clearing price provided by manager
     * @param _isAuctionBuying is crab buying or selling oSQTH
     */
    function _checkOTCPrice(uint256 _price, bool _isAuctionBuying) internal view {
        // Get twap
        uint256 squeethEthPrice = IOracle(oracle).getTwap(ethSqueethPool, sqth, weth, auctionTwapPeriod, true);

        if (_isAuctionBuying) {
            require(_price <= (squeethEthPrice * (1e18 + otcPriceTolerance)) / 1e18, "N21");
        } else {
            require(_price >= (squeethEthPrice * (1e18 - otcPriceTolerance)) / 1e18, "N22");
        }
    }

    function _checkCrabPrice(uint256 _price) internal view {
        // Get twap
        uint256 squeethEthPrice = IOracle(oracle).getTwap(ethSqueethPool, sqth, weth, auctionTwapPeriod, true);
        uint256 usdcEthPrice = IOracle(oracle).getTwap(ethUsdcPool, weth, usdc, auctionTwapPeriod, true);
        (,, uint256 collateral, uint256 debt) = ICrabStrategyV2(crab).getVaultDetails();
        uint256 crabFairPrice =
            ((collateral - ((debt * squeethEthPrice) / 1e18)) * usdcEthPrice) / ICrabStrategyV2(crab).totalSupply();
        crabFairPrice = crabFairPrice / 1e12; //converting from units of 18 to 6
        require(_price <= (crabFairPrice * (1e18 + otcPriceTolerance)) / 1e18, "N23");
        require(_price >= (crabFairPrice * (1e18 - otcPriceTolerance)) / 1e18, "N24");
    }

    function _calcFeeAdjustment() internal view returns (uint256) {
        uint256 feeRate = IController(sqthController).feeRate();
        if (feeRate == 0) return 0;
        uint256 squeethEthPrice = IOracle(oracle).getTwap(ethSqueethPool, sqth, weth, sqthTwapPeriod, true);
        return (squeethEthPrice * feeRate) / 10000;
    }

    receive() external payable {
        require(msg.sender == weth || msg.sender == crab, "N25");
    }
}

File 2 of 16 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

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

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

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

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

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

File 3 of 16 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC20.sol)

pragma solidity ^0.8.0;

import "../token/ERC20/IERC20.sol";

File 4 of 16 : 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 16 : 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 6 of 16 : Strings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)

pragma solidity ^0.8.0;

import "./math/Math.sol";

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

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

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

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

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

File 7 of 16 : ECDSA.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/cryptography/ECDSA.sol)

pragma solidity ^0.8.0;

import "../Strings.sol";

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
    enum RecoverError {
        NoError,
        InvalidSignature,
        InvalidSignatureLength,
        InvalidSignatureS,
        InvalidSignatureV // Deprecated in v4.8
    }

    function _throwError(RecoverError error) private pure {
        if (error == RecoverError.NoError) {
            return; // no error: do nothing
        } else if (error == RecoverError.InvalidSignature) {
            revert("ECDSA: invalid signature");
        } else if (error == RecoverError.InvalidSignatureLength) {
            revert("ECDSA: invalid signature length");
        } else if (error == RecoverError.InvalidSignatureS) {
            revert("ECDSA: invalid signature 's' value");
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature` or error string. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     *
     * Documentation for signature generation:
     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
     *
     * _Available since v4.3._
     */
    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
        if (signature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            /// @solidity memory-safe-assembly
            assembly {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
            return tryRecover(hash, v, r, s);
        } else {
            return (address(0), RecoverError.InvalidSignatureLength);
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, signature);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
     *
     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
     *
     * _Available since v4.3._
     */
    function tryRecover(
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal pure returns (address, RecoverError) {
        bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
        uint8 v = uint8((uint256(vs) >> 255) + 27);
        return tryRecover(hash, v, r, s);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
     *
     * _Available since v4.2._
     */
    function recover(
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, r, vs);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
     * `r` and `s` signature fields separately.
     *
     * _Available since v4.3._
     */
    function tryRecover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address, RecoverError) {
        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return (address(0), RecoverError.InvalidSignatureS);
        }

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        if (signer == address(0)) {
            return (address(0), RecoverError.InvalidSignature);
        }

        return (signer, RecoverError.NoError);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function recover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from a `hash`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
        // 32 is the length in bytes of hash,
        // enforced by the type signature above
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from `s`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
    }

    /**
     * @dev Returns an Ethereum Signed Typed Data, created from a
     * `domainSeparator` and a `structHash`. This produces hash corresponding
     * to the one signed with the
     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
     * JSON-RPC method as part of EIP-712.
     *
     * See {recover}.
     */
    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
    }
}

File 8 of 16 : EIP712.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./ECDSA.sol";

/**
 * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
 *
 * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,
 * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding
 * they need in their contracts using a combination of `abi.encode` and `keccak256`.
 *
 * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
 * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
 * ({_hashTypedDataV4}).
 *
 * The implementation of the domain separator was designed to be as efficient as possible while still properly updating
 * the chain id to protect against replay attacks on an eventual fork of the chain.
 *
 * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
 * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
 *
 * _Available since v3.4._
 */
abstract contract EIP712 {
    /* solhint-disable var-name-mixedcase */
    // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
    // invalidate the cached domain separator if the chain id changes.
    bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;
    uint256 private immutable _CACHED_CHAIN_ID;
    address private immutable _CACHED_THIS;

    bytes32 private immutable _HASHED_NAME;
    bytes32 private immutable _HASHED_VERSION;
    bytes32 private immutable _TYPE_HASH;

    /* solhint-enable var-name-mixedcase */

    /**
     * @dev Initializes the domain separator and parameter caches.
     *
     * The meaning of `name` and `version` is specified in
     * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
     *
     * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
     * - `version`: the current major version of the signing domain.
     *
     * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
     * contract upgrade].
     */
    constructor(string memory name, string memory version) {
        bytes32 hashedName = keccak256(bytes(name));
        bytes32 hashedVersion = keccak256(bytes(version));
        bytes32 typeHash = keccak256(
            "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
        );
        _HASHED_NAME = hashedName;
        _HASHED_VERSION = hashedVersion;
        _CACHED_CHAIN_ID = block.chainid;
        _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);
        _CACHED_THIS = address(this);
        _TYPE_HASH = typeHash;
    }

    /**
     * @dev Returns the domain separator for the current chain.
     */
    function _domainSeparatorV4() internal view returns (bytes32) {
        if (address(this) == _CACHED_THIS && block.chainid == _CACHED_CHAIN_ID) {
            return _CACHED_DOMAIN_SEPARATOR;
        } else {
            return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);
        }
    }

    function _buildDomainSeparator(
        bytes32 typeHash,
        bytes32 nameHash,
        bytes32 versionHash
    ) private view returns (bytes32) {
        return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));
    }

    /**
     * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
     * function returns the hash of the fully encoded EIP712 message for this domain.
     *
     * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
     *
     * ```solidity
     * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
     *     keccak256("Mail(address to,string contents)"),
     *     mailTo,
     *     keccak256(bytes(mailContents))
     * )));
     * address signer = ECDSA.recover(digest, signature);
     * ```
     */
    function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
        return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);
    }
}

File 9 of 16 : draft-EIP712.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

// EIP-712 is Final as of 2022-08-11. This file is deprecated.

import "./EIP712.sol";

File 10 of 16 : Math.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/math/Math.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

File 11 of 16 : IUniswapV3SwapCallback.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// @title Callback for IUniswapV3PoolActions#swap
/// @notice Any contract that calls IUniswapV3PoolActions#swap must implement this interface
interface IUniswapV3SwapCallback {
    /// @notice Called to `msg.sender` after executing a swap via IUniswapV3Pool#swap.
    /// @dev In the implementation you must pay the pool tokens owed for the swap.
    /// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory.
    /// amount0Delta and amount1Delta can both be 0 if no tokens were swapped.
    /// @param amount0Delta The amount of token0 that was sent (negative) or must be received (positive) by the pool by
    /// the end of the swap. If positive, the callback must send that amount of token0 to the pool.
    /// @param amount1Delta The amount of token1 that was sent (negative) or must be received (positive) by the pool by
    /// the end of the swap. If positive, the callback must send that amount of token1 to the pool.
    /// @param data Any data passed through by the caller via the IUniswapV3PoolActions#swap call
    function uniswapV3SwapCallback(
        int256 amount0Delta,
        int256 amount1Delta,
        bytes calldata data
    ) external;
}

File 12 of 16 : ISwapRouter.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.7.5;
pragma abicoder v2;

import '@uniswap/v3-core/contracts/interfaces/callback/IUniswapV3SwapCallback.sol';

/// @title Router token swapping functionality
/// @notice Functions for swapping tokens via Uniswap V3
interface ISwapRouter is IUniswapV3SwapCallback {
    struct ExactInputSingleParams {
        address tokenIn;
        address tokenOut;
        uint24 fee;
        address recipient;
        uint256 deadline;
        uint256 amountIn;
        uint256 amountOutMinimum;
        uint160 sqrtPriceLimitX96;
    }

    /// @notice Swaps `amountIn` of one token for as much as possible of another token
    /// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata
    /// @return amountOut The amount of the received token
    function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut);

    struct ExactInputParams {
        bytes path;
        address recipient;
        uint256 deadline;
        uint256 amountIn;
        uint256 amountOutMinimum;
    }

    /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path
    /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata
    /// @return amountOut The amount of the received token
    function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut);

    struct ExactOutputSingleParams {
        address tokenIn;
        address tokenOut;
        uint24 fee;
        address recipient;
        uint256 deadline;
        uint256 amountOut;
        uint256 amountInMaximum;
        uint160 sqrtPriceLimitX96;
    }

    /// @notice Swaps as little as possible of one token for `amountOut` of another token
    /// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata
    /// @return amountIn The amount of the input token
    function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn);

    struct ExactOutputParams {
        bytes path;
        address recipient;
        uint256 deadline;
        uint256 amountOut;
        uint256 amountInMaximum;
    }

    /// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed)
    /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata
    /// @return amountIn The amount of the input token
    function exactOutput(ExactOutputParams calldata params) external payable returns (uint256 amountIn);
}

File 13 of 16 : IController.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.17;

interface IController {
    function feeRate() external view returns (uint256);

    function TWAP_PERIOD() external view returns (uint32);

    function quoteCurrency() external view returns (address);

    function ethQuoteCurrencyPool() external view returns (address);

    function setFeeRate(uint256 _newFeeRate) external;

    function setFeeRecipient(address _newFeeRecipient) external;
}

File 14 of 16 : ICrabStrategyV2.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import {IERC20} from "openzeppelin/interfaces/IERC20.sol";

interface ICrabStrategyV2 is IERC20 {
    function getVaultDetails() external view returns (address, uint256, uint256, uint256);

    function deposit() external payable;

    function withdraw(uint256 _crabAmount) external;

    function flashDeposit(uint256 _ethToDeposit, uint24 _poolFee) external payable;

    function getWsqueethFromCrabAmount(uint256 _crabAmount) external view returns (uint256);

    function powerTokenController() external view returns (address);

    function weth() external view returns (address);

    function wPowerPerp() external view returns (address);

    function oracle() external view returns (address);

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

File 15 of 16 : IOracle.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

interface IOracle {
    function getTwap(address _pool, address _base, address _quote, uint32 _period, bool _checkPeriod)
        external
        view
        returns (uint256);
}

File 16 of 16 : IWETH.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import {IERC20} from "openzeppelin/interfaces/IERC20.sol";

interface IWETH is IERC20 {
    function deposit() external payable;

    function withdraw(uint256 wad) external;
}

Settings
{
  "remappings": [
    "@uniswap/v3-core/=lib/v3-core/",
    "@uniswap/v3-periphery/=lib/v3-periphery/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/",
    "openzeppelin/=lib/openzeppelin-contracts/contracts/",
    "squeeth-monorepo/=lib/squeeth-monorepo/packages/hardhat/contracts/",
    "v3-core/=lib/v3-core/",
    "v3-periphery/=lib/v3-periphery/contracts/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "london",
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_crab","type":"address"},{"internalType":"address","name":"_swapRouter","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"bidId","type":"uint256"},{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":false,"internalType":"uint256","name":"quantity","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isBuying","type":"bool"}],"name":"BidTraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"withdrawer","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"withdrawersBalance","type":"uint256"}],"name":"CrabDeQueued","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"withdrawer","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"withdrawersBalance","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"receiptIndex","type":"uint256"}],"name":"CrabQueued","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"withdrawer","type":"address"},{"indexed":false,"internalType":"uint256","name":"crabAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"usdcAmount","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"receiptIndex","type":"uint256"}],"name":"CrabWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"NonceTrue","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"previousTwap","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"newTwap","type":"uint32"}],"name":"SetAuctionTwapPeriod","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newDepositsIndex","type":"uint256"}],"name":"SetDepositsIndex","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"SetMinCrab","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"SetMinUSDC","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"previousTolerance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newOtcPriceTolerance","type":"uint256"}],"name":"SetOTCPriceTolerance","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newWithdrawsIndex","type":"uint256"}],"name":"SetWithdrawsIndex","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isAuctionLive","type":"bool"}],"name":"ToggledAuctionLive","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"depositor","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"depositorsBalance","type":"uint256"}],"name":"USDCDeQueued","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"depositor","type":"address"},{"indexed":false,"internalType":"uint256","name":"usdcAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"crabAmount","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"receiptIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"refundedETH","type":"uint256"}],"name":"USDCDeposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"depositor","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"depositorsBalance","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"receiptIndex","type":"uint256"}],"name":"USDCQueued","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"withdrawer","type":"address"},{"indexed":false,"internalType":"uint256","name":"crabAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"}],"name":"WithdrawRejected","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_OTC_PRICE_TOLERANCE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"auctionTwapPeriod","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"bidId","type":"uint256"},{"internalType":"address","name":"trader","type":"address"},{"internalType":"uint256","name":"quantity","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"bool","name":"isBuying","type":"bool"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct Order","name":"_order","type":"tuple"}],"name":"checkOrder","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[],"name":"crab","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"crabBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"depositsQueued","type":"uint256"},{"internalType":"uint256","name":"minEth","type":"uint256"},{"internalType":"uint256","name":"totalDeposit","type":"uint256"},{"components":[{"internalType":"uint256","name":"bidId","type":"uint256"},{"internalType":"address","name":"trader","type":"address"},{"internalType":"uint256","name":"quantity","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"bool","name":"isBuying","type":"bool"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct Order[]","name":"orders","type":"tuple[]"},{"internalType":"uint256","name":"clearingPrice","type":"uint256"},{"internalType":"uint256","name":"ethToFlashDeposit","type":"uint256"},{"internalType":"uint24","name":"ethUSDFee","type":"uint24"},{"internalType":"uint24","name":"flashDepositFee","type":"uint24"}],"internalType":"struct DepositAuctionParams","name":"_p","type":"tuple"}],"name":"depositAuction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"depositUSDC","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"deposits","outputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"depositsIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"depositsQueued","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bool","name":"_force","type":"bool"}],"name":"dequeueCrab","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"ethSqueethPool","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ethUsdcPool","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isAuctionLive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minCrabAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minUSDCAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_price","type":"uint256"},{"internalType":"uint256","name":"_quantity","type":"uint256"}],"name":"netAtPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"nonces","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oracle","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"otcPriceTolerance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"queueCrabForWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"i","type":"uint256"}],"name":"rejectWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_auctionTwapPeriod","type":"uint32"}],"name":"setAuctionTwapPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newDepositsIndex","type":"uint256"}],"name":"setDepositsIndex","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"setMinCrab","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"setMinUSDC","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nonce","type":"uint256"}],"name":"setNonceTrue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_otcPriceTolerance","type":"uint256"}],"name":"setOTCPriceTolerance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newWithdrawsIndex","type":"uint256"}],"name":"setWithdrawsIndex","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sqth","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sqthController","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sqthTwapPeriod","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"swapRouter","outputs":[{"internalType":"contract ISwapRouter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"toggleAuctionLive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"usdBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"usdc","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"userDepositsIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"userWithdrawsIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"crabToWithdraw","type":"uint256"},{"components":[{"internalType":"uint256","name":"bidId","type":"uint256"},{"internalType":"address","name":"trader","type":"address"},{"internalType":"uint256","name":"quantity","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"bool","name":"isBuying","type":"bool"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct Order[]","name":"orders","type":"tuple[]"},{"internalType":"uint256","name":"clearingPrice","type":"uint256"},{"internalType":"uint256","name":"minUSDC","type":"uint256"},{"internalType":"uint24","name":"ethUSDFee","type":"uint24"}],"internalType":"struct WithdrawAuctionParams","name":"_p","type":"tuple"}],"name":"withdrawAuction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bool","name":"_force","type":"bool"}],"name":"withdrawUSDC","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"withdraws","outputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawsIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawsQueued","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

6102806040526000805463ffffffff60a81b1916606960aa1b17905566b1a2bc2ec500006003553480156200003357600080fd5b50604051620068f4380380620068f4833981016040819052620000569162000728565b6040518060400160405280600b81526020016a435241424e657474696e6760a81b815250604051806040016040528060018152602001603160f81b815250620000ae620000a8620006b760201b60201c565b620006bb565b815160209283012081519183019190912060e08290526101008190524660a0818152604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f818801819052818301969096526060810194909452608080850193909352308483018190528151808603909301835260c0808601808452845194890194909420909452909252610120939093526001600160a01b038681166101808190529086166101e052633dcb0c5d60e01b909352519192633dcb0c5d9260c4808401938290030181865afa1580156200018e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001b4919062000760565b6001600160a01b03166102608190526040805163412b25e560e11b815290516382564bca916004808201926020929091908290030181865afa158015620001ff573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000225919062000760565b6001600160a01b0316610160816001600160a01b031681525050816001600160a01b0316633fc8cef36040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200027e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002a4919062000760565b6001600160a01b03166101a0816001600160a01b031681525050816001600160a01b0316637f07b1306040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002fd573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000323919062000760565b6001600160a01b03166101c0816001600160a01b031681525050816001600160a01b0316637dc0d1d06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200037c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003a2919062000760565b6001600160a01b0316610200816001600160a01b031681525050816001600160a01b0316634d76e6fc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620003fb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000421919062000760565b6001600160a01b0316610220816001600160a01b031681525050610260516001600160a01b0316634468c0226040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200047d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620004a3919062000760565b6001600160a01b0316610240816001600160a01b031681525050610260516001600160a01b0316637ca251846040518163ffffffff1660e01b8152600401602060405180830381865afa158015620004ff573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000525919062000785565b63ffffffff16610140526101c0516101805160405163095ea7b360e01b81526001600160a01b039182166004820152600019602482015291169063095ea7b3906044016020604051808303816000875af115801562000588573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620005ae9190620007ad565b506101a0516101e05160405163095ea7b360e01b81526001600160a01b039182166004820152600019602482015291169063095ea7b3906044016020604051808303816000875af115801562000608573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200062e9190620007ad565b50610160516101e05160405163095ea7b360e01b81526001600160a01b039182166004820152600019602482015291169063095ea7b3906044016020604051808303816000875af115801562000688573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620006ae9190620007ad565b505050620007d1565b3390565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80516001600160a01b03811681146200072357600080fd5b919050565b600080604083850312156200073c57600080fd5b62000747836200070b565b915062000757602084016200070b565b90509250929050565b6000602082840312156200077357600080fd5b6200077e826200070b565b9392505050565b6000602082840312156200079857600080fd5b815163ffffffff811681146200077e57600080fd5b600060208284031215620007c057600080fd5b815180151581146200077e57600080fd5b60805160a05160c05160e05161010051610120516101405161016051610180516101a0516101c0516101e05161020051610220516102405161026051615e6662000a8e600039600081816103c101526154d10152600081816108c30152818161159f01528181613c29015261514701526000818161078901528181614d040152818161505301526155aa01526000818161064c0152818161156a01528181613bf401528181614ccf0152818161501e01528181615118015261557d01526000818161087301528181611c5e0152613ec701526000818161097001528181611f5c0152818161202a01528181612229015281816136dd015281816137d201528181614d260152818161507501526155cc0152600081816102a7015281816104a4015281816115c10152818161192f01528181611a2101528181611bdf01528181611d010152818161245f015281816126c1015281816129ad015281816134230152818161392501528181613a3901528181613c4b01528181613d0d01528181613e2501528181614d48015281816150970152818161516801526155ee0152600081816102d9015281816104d801528181610add01528181610eb0015281816116eb01528181611dce01528181611eae015281816123cb015281816125d7015281816128c301528181612c4701528181612e0401528181612fae015281816134b4015281816138bf015281816145d901528181614eb20152818161522501526152af01526000818161047001528181611476015281816115e301528181611bba01528181612b8b0152818161318b0152818161332d01528181613c6d01528181613e4a0152818161406a015281816142030152818161479a01526151890152600081816106c0015261561001526000614a6901526000614ab801526000614a93015260006149ec01526000614a1601526000614a400152615e666000f3fe6080604052600436106102975760003560e01c80638da5cb5b1161015a578063d359e09e116100c1578063e9c3cb4f1161007a578063e9c3cb4f14610992578063ec13a775146109a8578063f0890dd5146109be578063f2fde38b146109d4578063f688bcfb146109f4578063f752549c14610a1457600080fd5b8063d359e09e146108b1578063d7fde229146108e5578063dc076e00146108fa578063dccb35c31461091e578063e28df0f81461093e578063e71716d21461095e57600080fd5b8063b15d566d11610113578063b15d566d146107e1578063ba53e9f214610801578063bb358d0114610821578063be20dc5614610841578063c31c9c0714610861578063cfa70b181461089557600080fd5b80638da5cb5b146107245780639e54bd94146107425780639ff69a5114610757578063a80a144514610777578063ab9f7c7f146107ab578063b02c43d0146107c157600080fd5b806355466c37116101fe578063771b4f7e116101b7578063771b4f7e1461061a5780637dc0d1d01461063a57806383cb98181461066e57806385fd0b601461068e5780638d1bbd9a146106ae5780638d86f60e146106f757600080fd5b806355466c371461054b5780635d35c81514610590578063616721a2146105b05780636b577714146105d05780636ec68625146105f0578063715018a61461060557600080fd5b80633d65fdac116102505780633d65fdac1461043e5780633e413bee1461045e5780633fc8cef3146104925780634285512d146104c65780634b277b22146104fa578063502e1a161461051057600080fd5b80631be19f4b146103395780632ad5314f1461036f57806330be6ca61461038f57806333fd7da7146103af578063351b7979146103fb5780633644e5151461041b57600080fd5b3661033457336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806102fb5750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b6103325760405162461bcd60e51b81526020600482015260036024820152624e323560e81b60448201526064015b60405180910390fd5b005b600080fd5b34801561034557600080fd5b5060005461035a90600160a01b900460ff1681565b60405190151581526020015b60405180910390f35b34801561037b57600080fd5b5061033261038a3660046158aa565b610a41565b34801561039b57600080fd5b506103326103aa3660046158aa565b610be4565b3480156103bb57600080fd5b506103e37f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610366565b34801561040757600080fd5b506103326104163660046158c3565b610c28565b34801561042757600080fd5b50610430610cd7565b604051908152602001610366565b34801561044a57600080fd5b506103326104593660046158aa565b610ce6565b34801561046a57600080fd5b506103e37f000000000000000000000000000000000000000000000000000000000000000081565b34801561049e57600080fd5b506103e37f000000000000000000000000000000000000000000000000000000000000000081565b3480156104d257600080fd5b506103e37f000000000000000000000000000000000000000000000000000000000000000081565b34801561050657600080fd5b5061043060025481565b34801561051c57600080fd5b5061035a61052b366004615915565b600c60209081526000928352604080842090915290825290205460ff1681565b34801561055757600080fd5b5061056b6105663660046158aa565b610d3b565b604080516001600160a01b039094168452602084019290925290820152606001610366565b34801561059c57600080fd5b506104306105ab366004615915565b610d78565b3480156105bc57600080fd5b506103326105cb3660046158aa565b610da9565b3480156105dc57600080fd5b506103326105eb3660046159a3565b610de6565b3480156105fc57600080fd5b50610430610df2565b34801561061157600080fd5b50610332610e4e565b34801561062657600080fd5b506103326106353660046158aa565b610e62565b34801561064657600080fd5b506103e37f000000000000000000000000000000000000000000000000000000000000000081565b34801561067a57600080fd5b50610430610689366004615915565b6110a2565b34801561069a57600080fd5b506103326106a93660046158aa565b6110be565b3480156106ba57600080fd5b506106e27f000000000000000000000000000000000000000000000000000000000000000081565b60405163ffffffff9091168152602001610366565b34801561070357600080fd5b50610430610712366004615a3c565b60096020526000908152604090205481565b34801561073057600080fd5b506000546001600160a01b03166103e3565b34801561074e57600080fd5b506104306110fb565b34801561076357600080fd5b506103326107723660046158aa565b611151565b34801561078357600080fd5b506103e37f000000000000000000000000000000000000000000000000000000000000000081565b3480156107b757600080fd5b5061043060045481565b3480156107cd57600080fd5b5061056b6107dc3660046158aa565b6111d5565b3480156107ed57600080fd5b506103326107fc366004615a59565b6111e5565b34801561080d57600080fd5b5061033261081c366004615a89565b611540565b34801561082d57600080fd5b5061033261083c366004615ac5565b612b43565b34801561084d57600080fd5b5061033261085c366004615ae7565b6133f4565b34801561086d57600080fd5b506103e37f000000000000000000000000000000000000000000000000000000000000000081565b3480156108a157600080fd5b506104306702c68af0bb14000081565b3480156108bd57600080fd5b506103e37f000000000000000000000000000000000000000000000000000000000000000081565b3480156108f157600080fd5b506103326142da565b34801561090657600080fd5b506000546106e290600160a81b900463ffffffff1681565b34801561092a57600080fd5b50610332610939366004615a59565b614348565b34801561094a57600080fd5b506103326109593660046158aa565b614699565b34801561096a57600080fd5b506103e37f000000000000000000000000000000000000000000000000000000000000000081565b34801561099e57600080fd5b5061043060035481565b3480156109b457600080fd5b5061043060055481565b3480156109ca57600080fd5b5061043060015481565b3480156109e057600080fd5b506103326109ef366004615a3c565b6146d6565b348015610a0057600080fd5b50610332610a0f3660046158aa565b61474c565b348015610a2057600080fd5b50610430610a2f366004615a3c565b60086020526000908152604090205481565b610a49614985565b600060078281548110610a5e57610a5e615b22565b6000918252602080832060408051606081018252600390940290910180546001600160a01b0316808552600182015485850181905260029092015485840152855260099092528320805492945090929091610aba908490615b4e565b90915550508051602082015160405163a9059cbb60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169263a9059cbb92610b1092600401615b61565b6020604051808303816000875af1158015610b2f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b539190615b7a565b5060078281548110610b6757610b67615b22565b6000918252602080832060039290920290910180546001600160a01b03191681556001810183905560020191909155815182820151604080519182529281018590526001600160a01b03909116917f33bb4dad7b0e24e5b68b61b81e08d26918ca45368d5e884dbca27a0492b25ca1910160405180910390a25050565b610bec614985565b60028190556040518181527f9cd4637c18a5aa90dc4d6494990c2c947b3ac1b1fb3e501859b07dc837647f28906020015b60405180910390a150565b610c30614985565b60b48163ffffffff161015610c6d5760405162461bcd60e51b815260206004820152600360248201526209c62760eb1b6044820152606401610329565b6000805463ffffffff838116600160a81b81810263ffffffff60a81b1985161790945560408051949093049091168084526020840191909152917f0c822eb813f3e206482238798fc18dac04c64d5d1f7aa04902764a561fb49dec91015b60405180910390a15050565b6000610ce16149df565b905090565b336000818152600c6020908152604080832085845290915290819020805460ff19166001179055517fb08bc192d897ee2c202636edceef256b6c873aab9cb3dbac5d02f143180806e091610c1d918490615b61565b60078181548110610d4b57600080fd5b60009182526020909120600390910201805460018201546002909201546001600160a01b03909116925083565b600b6020528160005260406000208181548110610d9457600080fd5b90600052602060002001600091509150505481565b610db1614985565b60048190556040518181527fedd711fc4c4d0010fe15757bd2c5cb3e0e739d37a662f9e691c1c1129187162690602001610c1d565b610def81614b06565b50565b600554600090815b600754821015610e485760078281548110610e1757610e17615b22565b90600052602060002090600302016001015481610e349190615b97565b905081610e4081615baa565b925050610dfa565b92915050565b610e56614985565b610e606000614c6c565b565b600254811015610e995760405162461bcd60e51b81526020600482015260026024820152614e3560f01b6044820152606401610329565b6040516323b872dd60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906323b872dd90610ee990339030908690600401615bc3565b6020604051808303816000875af1158015610f08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f2c9190615b7a565b5033600090815260096020526040902054610f48908290615b97565b33600081815260096020908152604080832094909455835160608101855283815280820186815242828701908152600780546001808201835582885294517fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c688600390920291820180546001600160a01b0319166001600160a01b0390921691909117905592517fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c68984015590517fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c68a90920191909155938352600b9091529290209054909161103491615b4e565b8154600181810184556000938452602090932001556007546110569190615b4e565b33600081815260096020908152604091829020548251868152918201527fa0b20c5744bd90bfa023d069a8d9eb19eb0c126373e9d4b2197265d902da387f91015b60405180910390a350565b600a6020528160005260406000208181548110610d9457600080fd5b6110c6614985565b60058190556040518181527f7e92dd6744ac55122826169c9cc551bffc2f89dfeab43add7a384ae3a2c260d290602001610c1d565b600454600090815b600654821015610e48576006828154811061112057611120615b22565b9060005260206000209060030201600101548161113d9190615b97565b90508161114981615baa565b925050611103565b611159614985565b6702c68af0bb1400008111156111975760405162461bcd60e51b81526020600482015260036024820152624e313960e81b6044820152606401610329565b600380549082905560408051828152602081018490527fdc2bec2c9994acf58f0642c15c46b46d91d42495bd1c2fb789b56277f5e6ba899101610ccb565b60068181548110610d4b57600080fd5b600054600160a01b900460ff1615806111fb5750805b61122c5760405162461bcd60e51b8152602060048201526002602482015261271960f11b6044820152606401610329565b33600090815260086020526040902054611247908390615b4e565b336000908152600860205260409020819055600154111580611276575033600090815260086020526040902054155b6112a75760405162461bcd60e51b81526020600482015260026024820152614e3360f01b6044820152606401610329565b336000908152600a60205260409020548290805b801561145e57336000908152600a602052604081206006906112de600185615b4e565b815481106112ee576112ee615b22565b90600052602060002001548154811061130957611309615b22565b9060005260206000209060030201905084156113645760028101546113319062093a80615b97565b42116113645760405162461bcd60e51b8152602060048201526002602482015261138d60f21b6044820152606401610329565b838160010154111561139457838160010160008282546113849190615b4e565b909155506000945061145e915050565b60018101546113a39085615b4e565b336000908152600a602052604090209094506006906113c3600185615b4e565b815481106113d3576113d3615b22565b9060005260206000200154815481106113ee576113ee615b22565b60009182526020808320600390920290910180546001600160a01b031916815560018101839055600201829055338252600a90526040902080548061143557611435615be7565b60019003818190600052602060002001600090559055508061145681615bfd565b9150506112bb565b5060405163a9059cbb60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906114ad9033908890600401615b61565b6020604051808303816000875af11580156114cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114f09190615b7a565b5033600081815260086020908152604091829020548251888152918201527f01cc9a8d1d62713e2bad4a1df8670605f491c86ab26bbe23f72dd6609d3f7ba491015b60405180910390a250505050565b611548614985565b61155781608001356000614cbc565b6000805460405163cce79bd560e01b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169163cce79bd59161161d917f0000000000000000000000000000000000000000000000000000000000000000917f0000000000000000000000000000000000000000000000000000000000000000917f000000000000000000000000000000000000000000000000000000000000000091600160a81b90910463ffffffff1690600190600401615c14565b602060405180830381865afa15801561163a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061165e9190615c4d565b9050816020013581600354670de0b6b3a764000061167c9190615b4e565b611687908535615c66565b6116969064e8d4a51000615c66565b6116a09190615c7d565b106116d35760405162461bcd60e51b81526020600482015260036024820152624e313160e81b6044820152606401610329565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561173a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061175e9190615c4d565b90504760006117706040860135614ea0565b90508060005b6117836060880188615c9f565b9050811015611b70576117996060880188615c9f565b828181106117a9576117a9615b22565b9050610140020160800160208101906117c29190615cf0565b6117f45760405162461bcd60e51b815260206004820152600360248201526227189960e91b6044820152606401610329565b60808701356118066060890189615c9f565b8381811061181657611816615b22565b905061014002016060013510156118555760405162461bcd60e51b81526020600482015260036024820152624e313360e81b6044820152606401610329565b6118916118656060890189615c9f565b8381811061187557611875615b22565b9050610140020180360381019061188c91906159a3565b614b06565b6118f76118a16060890189615c9f565b838181106118b1576118b1615b22565b9050610140020160200160208101906118ca9190615a3c565b6118d760608a018a615c9f565b848181106118e7576118e7615b22565b9050610140020160c00135614f81565b816119056060890189615c9f565b8381811061191557611915615b22565b905061014002016040013510611a17576001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166323b872dd61196160608a018a615c9f565b8481811061197157611971615b22565b90506101400201602001602081019061198a9190615a3c565b30670de0b6b3a76400006119a260808d013588615c66565b6119ac9190615c7d565b6040518463ffffffff1660e01b81526004016119ca93929190615bc3565b6020604051808303816000875af11580156119e9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a0d9190615b7a565b5060009150611b70565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166323b872dd611a5360608a018a615c9f565b84818110611a6357611a63615b22565b905061014002016020016020810190611a7c9190615a3c565b30670de0b6b3a764000060808c0135611a9860608e018e615c9f565b88818110611aa857611aa8615b22565b9050610140020160400135611abd9190615c66565b611ac79190615c7d565b6040518463ffffffff1660e01b8152600401611ae593929190615bc3565b6020604051808303816000875af1158015611b04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b289190615b7a565b50611b366060880188615c9f565b82818110611b4657611b46615b22565b905061014002016040013582611b5c9190615b4e565b915080611b6881615baa565b915050611776565b508015611ba55760405162461bcd60e51b8152602060048201526003602482015262138c4d60ea1b6044820152606401610329565b60408051610100810182526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811682527f00000000000000000000000000000000000000000000000000000000000000001660208201526000918101611c1960e08a0160c08b01615d0d565b62ffffff168152602001306001600160a01b03168152602001428152602001886000013581526020018860200135815260200160006001600160a01b031681525090507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663414bf389826040518263ffffffff1660e01b8152600401611ca89190615d32565b6020604051808303816000875af1158015611cc7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ceb9190615c4d565b506040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d9082906370a0823190602401602060405180830381865afa158015611d58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d7c9190615c4d565b6040518263ffffffff1660e01b8152600401611d9a91815260200190565b600060405180830381600087803b158015611db457600080fd5b505af1158015611dc8573d6000803e3d6000fd5b505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db088604001356040518263ffffffff1660e01b81526004016000604051808303818588803b158015611e2b57600080fd5b505af1158015611e3f573d6000803e3d6000fd5b5050505050611e6860405180606001604052806000815260200160008152602001600081525090565b611e728547615b4e565b6020820181905215801590611e8b575060008860a00135115b15611f47578760a00135816020015111611f475760208101516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063fc5b73ff9060a08b0135611eeb6101008d0160e08e01615d0d565b6040516001600160e01b031960e086901b168152600481019290925262ffffff1660248201526044016000604051808303818588803b158015611f2d57600080fd5b505af1158015611f41573d6000803e3d6000fd5b50505050505b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015611fab573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fcf9190615c4d565b60408201819052925060005b611fe860608a018a615c9f565b90508110156123aa5783611fff60608b018b615c9f565b8381811061200f5761200f615b22565b9050610140020160400135101561221f576001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663a9059cbb61205c60608c018c615c9f565b8481811061206c5761206c615b22565b9050610140020160200160208101906120859190615a3c565b61209260608d018d615c9f565b858181106120a2576120a2615b22565b90506101400201604001356040518363ffffffff1660e01b81526004016120ca929190615b61565b6020604051808303816000875af11580156120e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061210d9190615b7a565b5061211b60608a018a615c9f565b8281811061212b5761212b615b22565b9050610140020160400135846121419190615b4e565b935061215060608a018a615c9f565b8281811061216057612160615b22565b9050610140020160200160208101906121799190615a3c565b6001600160a01b031661218f60608b018b615c9f565b8381811061219f5761219f615b22565b61014002919091013590507fd1d072f838d64d5c63545bc6cf88a03b39fd711611b7df5b0c0822f745044fcc6121d860608d018d615c9f565b858181106121e8576121e8615b22565b6040805161014090920293909301830135815260808f013560208201526001928101929092525060600160405180910390a3612398565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663a9059cbb61225b60608c018c615c9f565b8481811061226b5761226b615b22565b9050610140020160200160208101906122849190615a3c565b866040518363ffffffff1660e01b81526004016122a2929190615b61565b6020604051808303816000875af11580156122c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122e59190615b7a565b506122f360608a018a615c9f565b8281811061230357612303615b22565b90506101400201602001602081019061231c9190615a3c565b6001600160a01b031661233260608b018b615c9f565b8381811061234257612342615b22565b6040805189815260808f013560208201526001818301529051610140929092029390930135927fd1d072f838d64d5c63545bc6cf88a03b39fd711611b7df5b0c0822f745044fcc925081900360600190a36123aa565b806123a281615baa565b915050611fdb565b50600480546040516370a0823160e01b8152309281019290925289359188907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561241a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061243e9190615c4d565b6124489190615b4e565b83526124548747615b4e565b8360200181815250507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db084602001516040518263ffffffff1660e01b81526004016000604051808303818588803b1580156124bc57600080fd5b505af11580156124d0573d6000803e3d6000fd5b50505050505b8115612b28576000600682815481106124f1576124f1615b22565b906000526020600020906003020160010154905061252960405180606001604052806000815260200160008152602001600081525090565b81600003612545578261253b81615baa565b93505050506124d6565b838211612844576125568285615b4e565b935081600860006006868154811061257057612570615b22565b600091825260208083206003909202909101546001600160a01b03168352820192909252604001812080549091906125a9908490615b4e565b909155505084518c35906125bd9084615c66565b6125c79190615c7d565b8152600680546001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163a9059cbb918690811061260e5761260e615b22565b600091825260209091206003909102015483516040516001600160e01b031960e085901b16815261264c926001600160a01b03169190600401615b61565b6020604051808303816000875af115801561266b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061268f9190615b7a565b5060208501518c35906126a29084615c66565b6126ac9190615c7d565b6020820181905264e8d4a51000101561278b577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb6006858154811061270157612701615b22565b600091825260209182902060039091020154908401516040516001600160e01b031960e085901b168152612742926001600160a01b03169190600401615b61565b6020604051808303816000875af1158015612761573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127859190615b7a565b50612793565b600060208201525b82600684815481106127a7576127a7615b22565b600091825260209182902060039190910201548351848301516040805188815294850192909252908301526001600160a01b031690600080516020615df18339815191529060600160405180910390a36006838154811061280a5761280a615b22565b60009182526020822060039091020180546001600160a01b031916815560018101829055600201558261283c81615baa565b935050612b21565b83600860006006868154811061285c5761285c615b22565b600091825260208083206003909202909101546001600160a01b0316835282019290925260400181208054909190612895908490615b4e565b909155505084518c35906128a99086615c66565b6128b39190615c7d565b8152600680546001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163a9059cbb91869081106128fa576128fa615b22565b600091825260209091206003909102015483516040516001600160e01b031960e085901b168152612938926001600160a01b03169190600401615b61565b6020604051808303816000875af1158015612957573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061297b9190615b7a565b5060208501518c359061298e9086615c66565b6129989190615c7d565b6020820181905264e8d4a510001015612a77577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb600685815481106129ed576129ed615b22565b600091825260209182902060039091020154908401516040516001600160e01b031960e085901b168152612a2e926001600160a01b03169190600401615b61565b6020604051808303816000875af1158015612a4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a719190615b7a565b50612a7f565b600060208201525b8260068481548110612a9357612a93615b22565b60009182526020918290206003919091020154835184830151604080518a815294850192909252908301526001600160a01b031690600080516020615df18339815191529060600160405180910390a38360068481548110612af757612af7615b22565b90600052602060002090600302016001016000828254612b179190615b4e565b9091555060009450505b50506124d6565b60045550506000805460ff60a01b1916905550505050505050565b612b4b614985565b612b548261500b565b600082612b6983670de0b6b3a7640000615c66565b612b739190615c7d565b6040516370a0823160e01b81523060048201529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015612bda573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bfe9190615c4d565b821115612c325760405162461bcd60e51b81526020600482015260026024820152614e3760f01b6044820152606401610329565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015612c96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cba9190615c4d565b811115612cee5760405162461bcd60e51b815260206004820152600260248201526109c760f31b6044820152606401610329565b60045460005b831561306f57600060068381548110612d0f57612d0f615b22565b6000918252602080832060408051606081018252600390940290910180546001600160a01b03168452600181015492840183905260020154908301529092509003612d675782612d5e81615baa565b93505050612cf4565b84816020015111612f0c576020810151612d819086615b4e565b945080602001516008600083600001516001600160a01b03166001600160a01b031681526020019081526020016000206000828254612dc09190615b4e565b909155505060208101518690612dde90670de0b6b3a7640000615c66565b612de89190615c7d565b815160405163a9059cbb60e01b81529193506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163a9059cbb91612e39918690600401615b61565b6020604051808303816000875af1158015612e58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e7c9190615b7a565b50805160208083015160408051918252918101859052600081830152905185926001600160a01b031691600080516020615df1833981519152919081900360600190a360068381548110612ed257612ed2615b22565b60009182526020822060039091020180546001600160a01b0319168155600181018290556002015582612f0481615baa565b935050613069565b848160200151612f1c9190615b4e565b60068481548110612f2f57612f2f615b22565b600091825260208083206001600390930201919091019290925582516001600160a01b031681526008909152604081208054879290612f6f908490615b4e565b90915550869050612f8886670de0b6b3a7640000615c66565b612f929190615c7d565b815160405163a9059cbb60e01b81529193506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163a9059cbb91612fe3918690600401615b61565b6020604051808303816000875af1158015613002573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130269190615b7a565b5080516040805187815260208101859052600081830152905185926001600160a01b031691600080516020615df1833981519152919081900360600190a3600094505b50612cf4565b600491909155600554905b82156133eb5760006007838154811061309557613095615b22565b6000918252602080832060408051606081018252600390940290910180546001600160a01b031684526001810154928401839052600201549083015290925090036130ed57826130e481615baa565b9350505061307a565b8381602001511161328b5760208101516131079085615b4e565b935080602001516009600083600001516001600160a01b03166001600160a01b0316815260200190815260200160002060008282546131469190615b4e565b90915550506020810151670de0b6b3a764000090613165908890615c66565b61316f9190615c7d565b815160405163a9059cbb60e01b81529193506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163a9059cbb916131c0918690600401615b61565b6020604051808303816000875af11580156131df573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132039190615b7a565b5080516020808301516040805191825291810185905285926001600160a01b031691600080516020615e11833981519152910160405180910390a36007838154811061325157613251615b22565b60009182526020822060039091020180546001600160a01b031916815560018101829055600201558261328381615baa565b9350506133e5565b83816020015161329b9190615b4e565b600784815481106132ae576132ae615b22565b600091825260208083206001600390930201919091019290925582516001600160a01b0316815260099091526040812080548692906132ee908490615b4e565b90915550670de0b6b3a764000090506133078786615c66565b6133119190615c7d565b815160405163a9059cbb60e01b81529193506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163a9059cbb91613362918690600401615b61565b6020604051808303816000875af1158015613381573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133a59190615b7a565b5080516020808301516040805191825291810185905285926001600160a01b031691600080516020615e11833981519152910160405180910390a3600093505b5061307a565b50600555505050565b6133fc614985565b61340b81604001356001614cbc565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015613472573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134969190615c4d565b60405163f73e19c360e01b81528335600482015290915047906000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063f73e19c390602401602060405180830381865afa158015613503573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135279190615c4d565b90508060005b61353a6020870187615c9f565b90508110801561354a5750600082115b156138a85761355f6118656020880188615c9f565b6135a561356f6020880188615c9f565b8381811061357f5761357f615b22565b9050610140020160200160208101906135989190615a3c565b6118d76020890189615c9f565b6135b26020870187615c9f565b828181106135c2576135c2615b22565b9050610140020160800160208101906135db9190615cf0565b1561360e5760405162461bcd60e51b81526020600482015260036024820152624e313560e81b6044820152606401610329565b60408601356136206020880188615c9f565b8381811061363057613630615b22565b9050610140020160600135111561366f5760405162461bcd60e51b815260206004820152600360248201526227189b60e91b6044820152606401610329565b8161367d6020880188615c9f565b8381811061368d5761368d615b22565b905061014002016040013510156137c8576136ab6020870187615c9f565b828181106136bb576136bb615b22565b9050610140020160400135826136d19190615b4e565b91506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166323b872dd61370f6020890189615c9f565b8481811061371f5761371f615b22565b9050610140020160200160208101906137389190615a3c565b3061374660208b018b615c9f565b8681811061375657613756615b22565b90506101400201604001356040518463ffffffff1660e01b815260040161377f93929190615bc3565b6020604051808303816000875af115801561379e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137c29190615b7a565b50613896565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166323b872dd6138046020890189615c9f565b8481811061381457613814615b22565b90506101400201602001602081019061382d9190615a3c565b30856040518463ffffffff1660e01b815260040161384d93929190615bc3565b6020604051808303816000875af115801561386c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138909190615b7a565b50600091505b806138a081615baa565b91505061352d565b50604051632e1a7d4d60e01b8152853560048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561390b57600080fd5b505af115801561391f573d6000803e3d6000fd5b505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0844761395e9190615b4e565b6040518263ffffffff1660e01b81526004016000604051808303818588803b15801561398957600080fd5b505af115801561399d573d6000803e3d6000fd5b508594506000935083925050505b6139b86020880188615c9f565b9050811080156139c85750600083115b15613be057826139db6020890189615c9f565b838181106139eb576139eb615b22565b90506101400201604001351015613a2b57613a096020880188615c9f565b82818110613a1957613a19615b22565b90506101400201604001359150613a2f565b8291505b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663a9059cbb613a6b60208a018a615c9f565b84818110613a7b57613a7b615b22565b905061014002016020016020810190613a949190615a3c565b670de0b6b3a7640000613aab60408c013587615c66565b613ab59190615c7d565b6040518363ffffffff1660e01b8152600401613ad2929190615b61565b6020604051808303816000875af1158015613af1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b159190615b7a565b50613b208284615b4e565b9250613b2f6020880188615c9f565b82818110613b3f57613b3f615b22565b905061014002016020016020810190613b589190615a3c565b6001600160a01b0316613b6e6020890189615c9f565b83818110613b7e57613b7e615b22565b604080518781528c82013560208201526000818301529051610140929092029390930135927fd1d072f838d64d5c63545bc6cf88a03b39fd711611b7df5b0c0822f745044fcc925081900360600190a380613bd881615baa565b9150506139ab565b506000805460405163cce79bd560e01b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169163cce79bd591613ca7917f0000000000000000000000000000000000000000000000000000000000000000917f0000000000000000000000000000000000000000000000000000000000000000917f000000000000000000000000000000000000000000000000000000000000000091600160a81b90910463ffffffff1690600190600401615c14565b602060405180830381865afa158015613cc4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ce89190615c4d565b6040516370a0823160e01b815230600482015290915060009087906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015613d54573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d789190615c4d565b613d829190615b4e565b9050876060013564e8d4a510006ec097ce7bc90715b34b9f1000000000600354670de0b6b3a7640000613db59190615b4e565b613dbf8686615c66565b613dc99190615c66565b613dd39190615c7d565b613ddd9190615c7d565b10613e105760405162461bcd60e51b81526020600482015260036024820152624e313760e81b6044820152606401610329565b60408051610100810182526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811682527f00000000000000000000000000000000000000000000000000000000000000001660208201526000918101613e8460a08c0160808d01615d0d565b62ffffff168152602001306001600160a01b031681526020014281526020018381526020018a60600135815260200160006001600160a01b0316815250905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663414bf389836040518263ffffffff1660e01b8152600401613f119190615d32565b6020604051808303816000875af1158015613f30573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f549190615c4d565b6005549091508a359060005b82156142bc57600060078381548110613f7b57613f7b615b22565b6000918252602080832060408051606081018252600390940290910180546001600160a01b03168452600181015492840183905260020154908301529092509003613fd35782613fca81615baa565b93505050613f60565b8381602001511161416a576020810151613fed9085615b4e565b935080602001516009600083600001516001600160a01b03166001600160a01b03168152602001908152602001600020600082825461402c9190615b4e565b909155505060208101518e3590614044908790615c66565b61404e9190615c7d565b815160405163a9059cbb60e01b81529193506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163a9059cbb9161409f918690600401615b61565b6020604051808303816000875af11580156140be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140e29190615b7a565b5080516020808301516040805191825291810185905285926001600160a01b031691600080516020615e11833981519152910160405180910390a36007838154811061413057614130615b22565b60009182526020822060039091020180546001600160a01b031916815560018101829055600201558261416281615baa565b9350506142b6565b836007848154811061417e5761417e615b22565b9060005260206000209060030201600101600082825461419e9190615b4e565b909155505080516001600160a01b0316600090815260096020526040812080548692906141cc908490615b4e565b90915550508d356141dd8686615c66565b6141e79190615c7d565b815160405163a9059cbb60e01b81529193506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163a9059cbb91614238918690600401615b61565b6020604051808303816000875af1158015614257573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061427b9190615b7a565b508051604080518681526020810185905285926001600160a01b031691600080516020615e11833981519152910160405180910390a3600093505b50613f60565b5060055550506000805460ff60a01b19169055505050505050505050565b6142e2614985565b6000805460ff600160a01b808304821615810260ff60a01b1990931692909217928390556040517fe6161233d7b23251971fb55c60874862ed7a143c115402afa8e1f2c07a131add9361433e9390049091161515815260200190565b60405180910390a1565b600054600160a01b900460ff16158061435e5750805b61438f5760405162461bcd60e51b8152602060048201526002602482015261271960f11b6044820152606401610329565b336000908152600960205260409020546143aa908390615b4e565b3360009081526009602052604090208190556002541115806143d9575033600090815260096020526040902054155b61440a5760405162461bcd60e51b8152602060048201526002602482015261271b60f11b6044820152606401610329565b336000908152600b60205260409020548290805b80156145c157336000908152600b60205260408120600790614441600185615b4e565b8154811061445157614451615b22565b90600052602060002001548154811061446c5761446c615b22565b9060005260206000209060030201905084156144c75760028101546144949062093a80615b97565b42116144c75760405162461bcd60e51b8152602060048201526002602482015261138d60f21b6044820152606401610329565b83816001015411156144f757838160010160008282546144e79190615b4e565b90915550600094506145c1915050565b60018101546145069085615b4e565b336000908152600b60205260409020909450600790614526600185615b4e565b8154811061453657614536615b22565b90600052602060002001548154811061455157614551615b22565b60009182526020808320600390920290910180546001600160a01b031916815560018101839055600201829055338252600b90526040902080548061459857614598615be7565b6001900381819060005260206000200160009055905550806145b981615bfd565b91505061441e565b5060405163a9059cbb60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906146109033908890600401615b61565b6020604051808303816000875af115801561462f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146539190615b7a565b5033600081815260096020908152604091829020548251888152918201527f4f4b6ab83d39fce2cc703aa2ac1d003ccd5b4781b4a561c1c586ef2e84e4d8cb9101611532565b6146a1614985565b60018190556040518181527f2217b276de774d686f6d9419505080eeee1f2a9e95ef298c5b4266f56eb6272790602001610c1d565b6146de614985565b6001600160a01b0381166147435760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610329565b610def81614c6c565b6001548110156147835760405162461bcd60e51b81526020600482015260026024820152614e3160f01b6044820152606401610329565b6040516323b872dd60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906323b872dd906147d390339030908690600401615bc3565b6020604051808303816000875af11580156147f2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148169190615b7a565b5033600090815260086020526040902054614832908290615b97565b33600081815260086020908152604080832094909455835160608101855283815280820186815242828701908152600680546001808201835582885294517ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f600390920291820180546001600160a01b0319166001600160a01b0390921691909117905592517ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d4084015590517ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d4190920191909155938352600a9091529290209054909161491e91615b4e565b8154600181810184556000938452602090932001556006546149409190615b4e565b33600081815260086020908152604091829020548251868152918201527fcd8a16e288c9b610f6bd123e0ed3f6aa008681653a19936f37bb6b2feb17ee8f9101611097565b6000546001600160a01b03163314610e605760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610329565b6000306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148015614a3857507f000000000000000000000000000000000000000000000000000000000000000046145b15614a6257507f000000000000000000000000000000000000000000000000000000000000000090565b50604080517f00000000000000000000000000000000000000000000000000000000000000006020808301919091527f0000000000000000000000000000000000000000000000000000000000000000828401527f000000000000000000000000000000000000000000000000000000000000000060608301524660808301523060a0808401919091528351808403909101815260c0909201909252805191012090565b60007fc8aea8e60353611f3ed5409dad2d3173390bd252431198e7300eda67fefb66b1826000015183602001518460400151856060015186608001518760a001518860c00151604051602001614b9f98979695949392919097885260208801969096526001600160a01b0394909416604087015260608601929092526080850152151560a084015260c083015260e08201526101000190565b6040516020818303038152906040528051906020012090506000614bc282615456565b90506000614be0828560e001518661010001518761012001516154a4565b905083602001516001600160a01b0316816001600160a01b031614614c2c5760405162461bcd60e51b81526020600482015260026024820152614e3960f01b6044820152606401610329565b428460a001511015614c665760405162461bcd60e51b815260206004820152600360248201526204e31360ec1b6044820152606401610329565b50505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000805460405163cce79bd560e01b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169163cce79bd591614d82917f0000000000000000000000000000000000000000000000000000000000000000917f0000000000000000000000000000000000000000000000000000000000000000917f000000000000000000000000000000000000000000000000000000000000000091600160a81b90910463ffffffff1690600190600401615c14565b602060405180830381865afa158015614d9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614dc39190615c4d565b90508115614e3857670de0b6b3a7640000600354670de0b6b3a7640000614dea9190615b97565b614df49083615c66565b614dfe9190615c7d565b831115614e335760405162461bcd60e51b81526020600482015260036024820152624e323160e81b6044820152606401610329565b505050565b670de0b6b3a7640000600354670de0b6b3a7640000614e579190615b4e565b614e619083615c66565b614e6b9190615c7d565b831015614e335760405162461bcd60e51b815260206004820152600360248201526227191960e91b6044820152606401610329565b600080614eab6154cc565b90506000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663533092ef6040518163ffffffff1660e01b8152600401608060405180830381865afa158015614f0e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614f329190615d9b565b9350935050506000670de0b6b3a76400008483614f4f9190615c66565b614f599190615c7d565b614f639084615b97565b614f6d8388615c66565b614f779190615c7d565b9695505050505050565b6001600160a01b0382166000908152600c6020908152604080832084845290915290205460ff1615614fdb5760405162461bcd60e51b815260206004820152600360248201526204e32360ec1b6044820152606401610329565b6001600160a01b039091166000908152600c6020908152604080832093835292905220805460ff19166001179055565b6000805460405163cce79bd560e01b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169163cce79bd5916150d1917f0000000000000000000000000000000000000000000000000000000000000000917f0000000000000000000000000000000000000000000000000000000000000000917f000000000000000000000000000000000000000000000000000000000000000091600160a81b90910463ffffffff1690600190600401615c14565b602060405180830381865afa1580156150ee573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906151129190615c4d565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663cce79bd57f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000600060159054906101000a900463ffffffff1660016040518663ffffffff1660e01b81526004016151dd959493929190615c14565b602060405180830381865afa1580156151fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061521e9190615c4d565b90506000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663533092ef6040518163ffffffff1660e01b8152600401608060405180830381865afa158015615281573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906152a59190615d9b565b93509350505060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561530b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061532f9190615c4d565b84670de0b6b3a76400006153438886615c66565b61534d9190615c7d565b6153579086615b4e565b6153619190615c66565b61536b9190615c7d565b905061537c64e8d4a5100082615c7d565b9050670de0b6b3a7640000600354670de0b6b3a764000061539d9190615b97565b6153a79083615c66565b6153b19190615c7d565b8611156153e65760405162461bcd60e51b81526020600482015260036024820152624e323360e81b6044820152606401610329565b670de0b6b3a7640000600354670de0b6b3a76400006154059190615b4e565b61540f9083615c66565b6154199190615c7d565b86101561544e5760405162461bcd60e51b8152602060048201526003602482015262138c8d60ea1b6044820152606401610329565b505050505050565b6000610e486154636149df565b8360405161190160f01b6020820152602281018390526042810182905260009060620160405160208183030381529060405280519060200120905092915050565b60008060006154b58787878761569c565b915091506154c281615760565b5095945050505050565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663978bbdb96040518163ffffffff1660e01b8152600401602060405180830381865afa15801561552d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906155519190615c4d565b90508060000361556357600091505090565b60405163cce79bd560e01b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063cce79bd59061563b907f0000000000000000000000000000000000000000000000000000000000000000907f0000000000000000000000000000000000000000000000000000000000000000907f0000000000000000000000000000000000000000000000000000000000000000907f000000000000000000000000000000000000000000000000000000000000000090600190600401615c14565b602060405180830381865afa158015615658573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061567c9190615c4d565b905061271061568b8383615c66565b6156959190615c7d565b9250505090565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156156d35750600090506003615757565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015615727573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811661575057600060019250925050615757565b9150600090505b94509492505050565b600081600481111561577457615774615dda565b0361577c5750565b600181600481111561579057615790615dda565b036157dd5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610329565b60028160048111156157f1576157f1615dda565b0361583e5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610329565b600381600481111561585257615852615dda565b03610def5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610329565b6000602082840312156158bc57600080fd5b5035919050565b6000602082840312156158d557600080fd5b813563ffffffff811681146158e957600080fd5b9392505050565b6001600160a01b0381168114610def57600080fd5b8035615910816158f0565b919050565b6000806040838503121561592857600080fd5b8235615933816158f0565b946020939093013593505050565b604051610140810167ffffffffffffffff8111828210171561597357634e487b7160e01b600052604160045260246000fd5b60405290565b8015158114610def57600080fd5b803561591081615979565b803560ff8116811461591057600080fd5b600061014082840312156159b657600080fd5b6159be615941565b823581526159ce60208401615905565b602082015260408301356040820152606083013560608201526159f360808401615987565b608082015260a083013560a082015260c083013560c0820152615a1860e08401615992565b60e08201526101008381013590820152610120928301359281019290925250919050565b600060208284031215615a4e57600080fd5b81356158e9816158f0565b60008060408385031215615a6c57600080fd5b823591506020830135615a7e81615979565b809150509250929050565b600060208284031215615a9b57600080fd5b813567ffffffffffffffff811115615ab257600080fd5b820161010081850312156158e957600080fd5b60008060408385031215615ad857600080fd5b50508035926020909101359150565b600060208284031215615af957600080fd5b813567ffffffffffffffff811115615b1057600080fd5b820160a081850312156158e957600080fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b81810381811115610e4857610e48615b38565b6001600160a01b03929092168252602082015260400190565b600060208284031215615b8c57600080fd5b81516158e981615979565b80820180821115610e4857610e48615b38565b600060018201615bbc57615bbc615b38565b5060010190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b634e487b7160e01b600052603160045260246000fd5b600081615c0c57615c0c615b38565b506000190190565b6001600160a01b039586168152938516602085015291909316604083015263ffffffff9092166060820152901515608082015260a00190565b600060208284031215615c5f57600080fd5b5051919050565b8082028115828204841417610e4857610e48615b38565b600082615c9a57634e487b7160e01b600052601260045260246000fd5b500490565b6000808335601e19843603018112615cb657600080fd5b83018035915067ffffffffffffffff821115615cd157600080fd5b602001915061014081023603821315615ce957600080fd5b9250929050565b600060208284031215615d0257600080fd5b81356158e981615979565b600060208284031215615d1f57600080fd5b813562ffffff811681146158e957600080fd5b81516001600160a01b03908116825260208084015182169083015260408084015162ffffff16908301526060808401518216908301526080808401519083015260a0838101519083015260c0808401519083015260e09283015116918101919091526101000190565b60008060008060808587031215615db157600080fd5b8451615dbc816158f0565b60208601516040870151606090970151919890975090945092505050565b634e487b7160e01b600052602160045260246000fdfef407c5a0c99a9a3d15fe5a46a4aba5ce747e855b58bc1aec4a589fd53bda599e460140ba175e3953a9d581c92fd2fc50c428691b4220431ff4a3f08c62aa3906a2646970667358221220851c03f17b6117b7277341d79c60c79cc765d347623650558859db49b5afd68d64736f6c634300081100330000000000000000000000003b960e47784150f5a63777201ee2b15253d713e8000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564

Deployed Bytecode

0x6080604052600436106102975760003560e01c80638da5cb5b1161015a578063d359e09e116100c1578063e9c3cb4f1161007a578063e9c3cb4f14610992578063ec13a775146109a8578063f0890dd5146109be578063f2fde38b146109d4578063f688bcfb146109f4578063f752549c14610a1457600080fd5b8063d359e09e146108b1578063d7fde229146108e5578063dc076e00146108fa578063dccb35c31461091e578063e28df0f81461093e578063e71716d21461095e57600080fd5b8063b15d566d11610113578063b15d566d146107e1578063ba53e9f214610801578063bb358d0114610821578063be20dc5614610841578063c31c9c0714610861578063cfa70b181461089557600080fd5b80638da5cb5b146107245780639e54bd94146107425780639ff69a5114610757578063a80a144514610777578063ab9f7c7f146107ab578063b02c43d0146107c157600080fd5b806355466c37116101fe578063771b4f7e116101b7578063771b4f7e1461061a5780637dc0d1d01461063a57806383cb98181461066e57806385fd0b601461068e5780638d1bbd9a146106ae5780638d86f60e146106f757600080fd5b806355466c371461054b5780635d35c81514610590578063616721a2146105b05780636b577714146105d05780636ec68625146105f0578063715018a61461060557600080fd5b80633d65fdac116102505780633d65fdac1461043e5780633e413bee1461045e5780633fc8cef3146104925780634285512d146104c65780634b277b22146104fa578063502e1a161461051057600080fd5b80631be19f4b146103395780632ad5314f1461036f57806330be6ca61461038f57806333fd7da7146103af578063351b7979146103fb5780633644e5151461041b57600080fd5b3661033457336001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21614806102fb5750336001600160a01b037f0000000000000000000000003b960e47784150f5a63777201ee2b15253d713e816145b6103325760405162461bcd60e51b81526020600482015260036024820152624e323560e81b60448201526064015b60405180910390fd5b005b600080fd5b34801561034557600080fd5b5060005461035a90600160a01b900460ff1681565b60405190151581526020015b60405180910390f35b34801561037b57600080fd5b5061033261038a3660046158aa565b610a41565b34801561039b57600080fd5b506103326103aa3660046158aa565b610be4565b3480156103bb57600080fd5b506103e37f00000000000000000000000064187ae08781b09368e6253f9e94951243a493d581565b6040516001600160a01b039091168152602001610366565b34801561040757600080fd5b506103326104163660046158c3565b610c28565b34801561042757600080fd5b50610430610cd7565b604051908152602001610366565b34801561044a57600080fd5b506103326104593660046158aa565b610ce6565b34801561046a57600080fd5b506103e37f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4881565b34801561049e57600080fd5b506103e37f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b3480156104d257600080fd5b506103e37f0000000000000000000000003b960e47784150f5a63777201ee2b15253d713e881565b34801561050657600080fd5b5061043060025481565b34801561051c57600080fd5b5061035a61052b366004615915565b600c60209081526000928352604080842090915290825290205460ff1681565b34801561055757600080fd5b5061056b6105663660046158aa565b610d3b565b604080516001600160a01b039094168452602084019290925290820152606001610366565b34801561059c57600080fd5b506104306105ab366004615915565b610d78565b3480156105bc57600080fd5b506103326105cb3660046158aa565b610da9565b3480156105dc57600080fd5b506103326105eb3660046159a3565b610de6565b3480156105fc57600080fd5b50610430610df2565b34801561061157600080fd5b50610332610e4e565b34801561062657600080fd5b506103326106353660046158aa565b610e62565b34801561064657600080fd5b506103e37f00000000000000000000000065d66c76447ccb45daf1e8044e918fa786a483a181565b34801561067a57600080fd5b50610430610689366004615915565b6110a2565b34801561069a57600080fd5b506103326106a93660046158aa565b6110be565b3480156106ba57600080fd5b506106e27f00000000000000000000000000000000000000000000000000000000000001a481565b60405163ffffffff9091168152602001610366565b34801561070357600080fd5b50610430610712366004615a3c565b60096020526000908152604090205481565b34801561073057600080fd5b506000546001600160a01b03166103e3565b34801561074e57600080fd5b506104306110fb565b34801561076357600080fd5b506103326107723660046158aa565b611151565b34801561078357600080fd5b506103e37f00000000000000000000000082c427adfdf2d245ec51d8046b41c4ee87f0d29c81565b3480156107b757600080fd5b5061043060045481565b3480156107cd57600080fd5b5061056b6107dc3660046158aa565b6111d5565b3480156107ed57600080fd5b506103326107fc366004615a59565b6111e5565b34801561080d57600080fd5b5061033261081c366004615a89565b611540565b34801561082d57600080fd5b5061033261083c366004615ac5565b612b43565b34801561084d57600080fd5b5061033261085c366004615ae7565b6133f4565b34801561086d57600080fd5b506103e37f000000000000000000000000e592427a0aece92de3edee1f18e0157c0586156481565b3480156108a157600080fd5b506104306702c68af0bb14000081565b3480156108bd57600080fd5b506103e37f0000000000000000000000008ad599c3a0ff1de082011efddc58f1908eb6e6d881565b3480156108f157600080fd5b506103326142da565b34801561090657600080fd5b506000546106e290600160a81b900463ffffffff1681565b34801561092a57600080fd5b50610332610939366004615a59565b614348565b34801561094a57600080fd5b506103326109593660046158aa565b614699565b34801561096a57600080fd5b506103e37f000000000000000000000000f1b99e3e573a1a9c5e6b2ce818b617f0e664e86b81565b34801561099e57600080fd5b5061043060035481565b3480156109b457600080fd5b5061043060055481565b3480156109ca57600080fd5b5061043060015481565b3480156109e057600080fd5b506103326109ef366004615a3c565b6146d6565b348015610a0057600080fd5b50610332610a0f3660046158aa565b61474c565b348015610a2057600080fd5b50610430610a2f366004615a3c565b60086020526000908152604090205481565b610a49614985565b600060078281548110610a5e57610a5e615b22565b6000918252602080832060408051606081018252600390940290910180546001600160a01b0316808552600182015485850181905260029092015485840152855260099092528320805492945090929091610aba908490615b4e565b90915550508051602082015160405163a9059cbb60e01b81526001600160a01b037f0000000000000000000000003b960e47784150f5a63777201ee2b15253d713e8169263a9059cbb92610b1092600401615b61565b6020604051808303816000875af1158015610b2f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b539190615b7a565b5060078281548110610b6757610b67615b22565b6000918252602080832060039290920290910180546001600160a01b03191681556001810183905560020191909155815182820151604080519182529281018590526001600160a01b03909116917f33bb4dad7b0e24e5b68b61b81e08d26918ca45368d5e884dbca27a0492b25ca1910160405180910390a25050565b610bec614985565b60028190556040518181527f9cd4637c18a5aa90dc4d6494990c2c947b3ac1b1fb3e501859b07dc837647f28906020015b60405180910390a150565b610c30614985565b60b48163ffffffff161015610c6d5760405162461bcd60e51b815260206004820152600360248201526209c62760eb1b6044820152606401610329565b6000805463ffffffff838116600160a81b81810263ffffffff60a81b1985161790945560408051949093049091168084526020840191909152917f0c822eb813f3e206482238798fc18dac04c64d5d1f7aa04902764a561fb49dec91015b60405180910390a15050565b6000610ce16149df565b905090565b336000818152600c6020908152604080832085845290915290819020805460ff19166001179055517fb08bc192d897ee2c202636edceef256b6c873aab9cb3dbac5d02f143180806e091610c1d918490615b61565b60078181548110610d4b57600080fd5b60009182526020909120600390910201805460018201546002909201546001600160a01b03909116925083565b600b6020528160005260406000208181548110610d9457600080fd5b90600052602060002001600091509150505481565b610db1614985565b60048190556040518181527fedd711fc4c4d0010fe15757bd2c5cb3e0e739d37a662f9e691c1c1129187162690602001610c1d565b610def81614b06565b50565b600554600090815b600754821015610e485760078281548110610e1757610e17615b22565b90600052602060002090600302016001015481610e349190615b97565b905081610e4081615baa565b925050610dfa565b92915050565b610e56614985565b610e606000614c6c565b565b600254811015610e995760405162461bcd60e51b81526020600482015260026024820152614e3560f01b6044820152606401610329565b6040516323b872dd60e01b81526001600160a01b037f0000000000000000000000003b960e47784150f5a63777201ee2b15253d713e816906323b872dd90610ee990339030908690600401615bc3565b6020604051808303816000875af1158015610f08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f2c9190615b7a565b5033600090815260096020526040902054610f48908290615b97565b33600081815260096020908152604080832094909455835160608101855283815280820186815242828701908152600780546001808201835582885294517fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c688600390920291820180546001600160a01b0319166001600160a01b0390921691909117905592517fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c68984015590517fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c68a90920191909155938352600b9091529290209054909161103491615b4e565b8154600181810184556000938452602090932001556007546110569190615b4e565b33600081815260096020908152604091829020548251868152918201527fa0b20c5744bd90bfa023d069a8d9eb19eb0c126373e9d4b2197265d902da387f91015b60405180910390a350565b600a6020528160005260406000208181548110610d9457600080fd5b6110c6614985565b60058190556040518181527f7e92dd6744ac55122826169c9cc551bffc2f89dfeab43add7a384ae3a2c260d290602001610c1d565b600454600090815b600654821015610e48576006828154811061112057611120615b22565b9060005260206000209060030201600101548161113d9190615b97565b90508161114981615baa565b925050611103565b611159614985565b6702c68af0bb1400008111156111975760405162461bcd60e51b81526020600482015260036024820152624e313960e81b6044820152606401610329565b600380549082905560408051828152602081018490527fdc2bec2c9994acf58f0642c15c46b46d91d42495bd1c2fb789b56277f5e6ba899101610ccb565b60068181548110610d4b57600080fd5b600054600160a01b900460ff1615806111fb5750805b61122c5760405162461bcd60e51b8152602060048201526002602482015261271960f11b6044820152606401610329565b33600090815260086020526040902054611247908390615b4e565b336000908152600860205260409020819055600154111580611276575033600090815260086020526040902054155b6112a75760405162461bcd60e51b81526020600482015260026024820152614e3360f01b6044820152606401610329565b336000908152600a60205260409020548290805b801561145e57336000908152600a602052604081206006906112de600185615b4e565b815481106112ee576112ee615b22565b90600052602060002001548154811061130957611309615b22565b9060005260206000209060030201905084156113645760028101546113319062093a80615b97565b42116113645760405162461bcd60e51b8152602060048201526002602482015261138d60f21b6044820152606401610329565b838160010154111561139457838160010160008282546113849190615b4e565b909155506000945061145e915050565b60018101546113a39085615b4e565b336000908152600a602052604090209094506006906113c3600185615b4e565b815481106113d3576113d3615b22565b9060005260206000200154815481106113ee576113ee615b22565b60009182526020808320600390920290910180546001600160a01b031916815560018101839055600201829055338252600a90526040902080548061143557611435615be7565b60019003818190600052602060002001600090559055508061145681615bfd565b9150506112bb565b5060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48169063a9059cbb906114ad9033908890600401615b61565b6020604051808303816000875af11580156114cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114f09190615b7a565b5033600081815260086020908152604091829020548251888152918201527f01cc9a8d1d62713e2bad4a1df8670605f491c86ab26bbe23f72dd6609d3f7ba491015b60405180910390a250505050565b611548614985565b61155781608001356000614cbc565b6000805460405163cce79bd560e01b81527f00000000000000000000000065d66c76447ccb45daf1e8044e918fa786a483a16001600160a01b03169163cce79bd59161161d917f0000000000000000000000008ad599c3a0ff1de082011efddc58f1908eb6e6d8917f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2917f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4891600160a81b90910463ffffffff1690600190600401615c14565b602060405180830381865afa15801561163a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061165e9190615c4d565b9050816020013581600354670de0b6b3a764000061167c9190615b4e565b611687908535615c66565b6116969064e8d4a51000615c66565b6116a09190615c7d565b106116d35760405162461bcd60e51b81526020600482015260036024820152624e313160e81b6044820152606401610329565b6040516370a0823160e01b81523060048201526000907f0000000000000000000000003b960e47784150f5a63777201ee2b15253d713e86001600160a01b0316906370a0823190602401602060405180830381865afa15801561173a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061175e9190615c4d565b90504760006117706040860135614ea0565b90508060005b6117836060880188615c9f565b9050811015611b70576117996060880188615c9f565b828181106117a9576117a9615b22565b9050610140020160800160208101906117c29190615cf0565b6117f45760405162461bcd60e51b815260206004820152600360248201526227189960e91b6044820152606401610329565b60808701356118066060890189615c9f565b8381811061181657611816615b22565b905061014002016060013510156118555760405162461bcd60e51b81526020600482015260036024820152624e313360e81b6044820152606401610329565b6118916118656060890189615c9f565b8381811061187557611875615b22565b9050610140020180360381019061188c91906159a3565b614b06565b6118f76118a16060890189615c9f565b838181106118b1576118b1615b22565b9050610140020160200160208101906118ca9190615a3c565b6118d760608a018a615c9f565b848181106118e7576118e7615b22565b9050610140020160c00135614f81565b816119056060890189615c9f565b8381811061191557611915615b22565b905061014002016040013510611a17576001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2166323b872dd61196160608a018a615c9f565b8481811061197157611971615b22565b90506101400201602001602081019061198a9190615a3c565b30670de0b6b3a76400006119a260808d013588615c66565b6119ac9190615c7d565b6040518463ffffffff1660e01b81526004016119ca93929190615bc3565b6020604051808303816000875af11580156119e9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a0d9190615b7a565b5060009150611b70565b6001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2166323b872dd611a5360608a018a615c9f565b84818110611a6357611a63615b22565b905061014002016020016020810190611a7c9190615a3c565b30670de0b6b3a764000060808c0135611a9860608e018e615c9f565b88818110611aa857611aa8615b22565b9050610140020160400135611abd9190615c66565b611ac79190615c7d565b6040518463ffffffff1660e01b8152600401611ae593929190615bc3565b6020604051808303816000875af1158015611b04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b289190615b7a565b50611b366060880188615c9f565b82818110611b4657611b46615b22565b905061014002016040013582611b5c9190615b4e565b915080611b6881615baa565b915050611776565b508015611ba55760405162461bcd60e51b8152602060048201526003602482015262138c4d60ea1b6044820152606401610329565b60408051610100810182526001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48811682527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21660208201526000918101611c1960e08a0160c08b01615d0d565b62ffffff168152602001306001600160a01b03168152602001428152602001886000013581526020018860200135815260200160006001600160a01b031681525090507f000000000000000000000000e592427a0aece92de3edee1f18e0157c058615646001600160a01b031663414bf389826040518263ffffffff1660e01b8152600401611ca89190615d32565b6020604051808303816000875af1158015611cc7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ceb9190615c4d565b506040516370a0823160e01b81523060048201527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031690632e1a7d4d9082906370a0823190602401602060405180830381865afa158015611d58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d7c9190615c4d565b6040518263ffffffff1660e01b8152600401611d9a91815260200190565b600060405180830381600087803b158015611db457600080fd5b505af1158015611dc8573d6000803e3d6000fd5b505050507f0000000000000000000000003b960e47784150f5a63777201ee2b15253d713e86001600160a01b031663d0e30db088604001356040518263ffffffff1660e01b81526004016000604051808303818588803b158015611e2b57600080fd5b505af1158015611e3f573d6000803e3d6000fd5b5050505050611e6860405180606001604052806000815260200160008152602001600081525090565b611e728547615b4e565b6020820181905215801590611e8b575060008860a00135115b15611f47578760a00135816020015111611f475760208101516001600160a01b037f0000000000000000000000003b960e47784150f5a63777201ee2b15253d713e8169063fc5b73ff9060a08b0135611eeb6101008d0160e08e01615d0d565b6040516001600160e01b031960e086901b168152600481019290925262ffffff1660248201526044016000604051808303818588803b158015611f2d57600080fd5b505af1158015611f41573d6000803e3d6000fd5b50505050505b6040516370a0823160e01b81523060048201527f000000000000000000000000f1b99e3e573a1a9c5e6b2ce818b617f0e664e86b6001600160a01b0316906370a0823190602401602060405180830381865afa158015611fab573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fcf9190615c4d565b60408201819052925060005b611fe860608a018a615c9f565b90508110156123aa5783611fff60608b018b615c9f565b8381811061200f5761200f615b22565b9050610140020160400135101561221f576001600160a01b037f000000000000000000000000f1b99e3e573a1a9c5e6b2ce818b617f0e664e86b1663a9059cbb61205c60608c018c615c9f565b8481811061206c5761206c615b22565b9050610140020160200160208101906120859190615a3c565b61209260608d018d615c9f565b858181106120a2576120a2615b22565b90506101400201604001356040518363ffffffff1660e01b81526004016120ca929190615b61565b6020604051808303816000875af11580156120e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061210d9190615b7a565b5061211b60608a018a615c9f565b8281811061212b5761212b615b22565b9050610140020160400135846121419190615b4e565b935061215060608a018a615c9f565b8281811061216057612160615b22565b9050610140020160200160208101906121799190615a3c565b6001600160a01b031661218f60608b018b615c9f565b8381811061219f5761219f615b22565b61014002919091013590507fd1d072f838d64d5c63545bc6cf88a03b39fd711611b7df5b0c0822f745044fcc6121d860608d018d615c9f565b858181106121e8576121e8615b22565b6040805161014090920293909301830135815260808f013560208201526001928101929092525060600160405180910390a3612398565b6001600160a01b037f000000000000000000000000f1b99e3e573a1a9c5e6b2ce818b617f0e664e86b1663a9059cbb61225b60608c018c615c9f565b8481811061226b5761226b615b22565b9050610140020160200160208101906122849190615a3c565b866040518363ffffffff1660e01b81526004016122a2929190615b61565b6020604051808303816000875af11580156122c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122e59190615b7a565b506122f360608a018a615c9f565b8281811061230357612303615b22565b90506101400201602001602081019061231c9190615a3c565b6001600160a01b031661233260608b018b615c9f565b8381811061234257612342615b22565b6040805189815260808f013560208201526001818301529051610140929092029390930135927fd1d072f838d64d5c63545bc6cf88a03b39fd711611b7df5b0c0822f745044fcc925081900360600190a36123aa565b806123a281615baa565b915050611fdb565b50600480546040516370a0823160e01b8152309281019290925289359188907f0000000000000000000000003b960e47784150f5a63777201ee2b15253d713e86001600160a01b0316906370a0823190602401602060405180830381865afa15801561241a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061243e9190615c4d565b6124489190615b4e565b83526124548747615b4e565b8360200181815250507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db084602001516040518263ffffffff1660e01b81526004016000604051808303818588803b1580156124bc57600080fd5b505af11580156124d0573d6000803e3d6000fd5b50505050505b8115612b28576000600682815481106124f1576124f1615b22565b906000526020600020906003020160010154905061252960405180606001604052806000815260200160008152602001600081525090565b81600003612545578261253b81615baa565b93505050506124d6565b838211612844576125568285615b4e565b935081600860006006868154811061257057612570615b22565b600091825260208083206003909202909101546001600160a01b03168352820192909252604001812080549091906125a9908490615b4e565b909155505084518c35906125bd9084615c66565b6125c79190615c7d565b8152600680546001600160a01b037f0000000000000000000000003b960e47784150f5a63777201ee2b15253d713e8169163a9059cbb918690811061260e5761260e615b22565b600091825260209091206003909102015483516040516001600160e01b031960e085901b16815261264c926001600160a01b03169190600401615b61565b6020604051808303816000875af115801561266b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061268f9190615b7a565b5060208501518c35906126a29084615c66565b6126ac9190615c7d565b6020820181905264e8d4a51000101561278b577f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663a9059cbb6006858154811061270157612701615b22565b600091825260209182902060039091020154908401516040516001600160e01b031960e085901b168152612742926001600160a01b03169190600401615b61565b6020604051808303816000875af1158015612761573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127859190615b7a565b50612793565b600060208201525b82600684815481106127a7576127a7615b22565b600091825260209182902060039190910201548351848301516040805188815294850192909252908301526001600160a01b031690600080516020615df18339815191529060600160405180910390a36006838154811061280a5761280a615b22565b60009182526020822060039091020180546001600160a01b031916815560018101829055600201558261283c81615baa565b935050612b21565b83600860006006868154811061285c5761285c615b22565b600091825260208083206003909202909101546001600160a01b0316835282019290925260400181208054909190612895908490615b4e565b909155505084518c35906128a99086615c66565b6128b39190615c7d565b8152600680546001600160a01b037f0000000000000000000000003b960e47784150f5a63777201ee2b15253d713e8169163a9059cbb91869081106128fa576128fa615b22565b600091825260209091206003909102015483516040516001600160e01b031960e085901b168152612938926001600160a01b03169190600401615b61565b6020604051808303816000875af1158015612957573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061297b9190615b7a565b5060208501518c359061298e9086615c66565b6129989190615c7d565b6020820181905264e8d4a510001015612a77577f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663a9059cbb600685815481106129ed576129ed615b22565b600091825260209182902060039091020154908401516040516001600160e01b031960e085901b168152612a2e926001600160a01b03169190600401615b61565b6020604051808303816000875af1158015612a4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a719190615b7a565b50612a7f565b600060208201525b8260068481548110612a9357612a93615b22565b60009182526020918290206003919091020154835184830151604080518a815294850192909252908301526001600160a01b031690600080516020615df18339815191529060600160405180910390a38360068481548110612af757612af7615b22565b90600052602060002090600302016001016000828254612b179190615b4e565b9091555060009450505b50506124d6565b60045550506000805460ff60a01b1916905550505050505050565b612b4b614985565b612b548261500b565b600082612b6983670de0b6b3a7640000615c66565b612b739190615c7d565b6040516370a0823160e01b81523060048201529091507f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0316906370a0823190602401602060405180830381865afa158015612bda573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bfe9190615c4d565b821115612c325760405162461bcd60e51b81526020600482015260026024820152614e3760f01b6044820152606401610329565b6040516370a0823160e01b81523060048201527f0000000000000000000000003b960e47784150f5a63777201ee2b15253d713e86001600160a01b0316906370a0823190602401602060405180830381865afa158015612c96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cba9190615c4d565b811115612cee5760405162461bcd60e51b815260206004820152600260248201526109c760f31b6044820152606401610329565b60045460005b831561306f57600060068381548110612d0f57612d0f615b22565b6000918252602080832060408051606081018252600390940290910180546001600160a01b03168452600181015492840183905260020154908301529092509003612d675782612d5e81615baa565b93505050612cf4565b84816020015111612f0c576020810151612d819086615b4e565b945080602001516008600083600001516001600160a01b03166001600160a01b031681526020019081526020016000206000828254612dc09190615b4e565b909155505060208101518690612dde90670de0b6b3a7640000615c66565b612de89190615c7d565b815160405163a9059cbb60e01b81529193506001600160a01b037f0000000000000000000000003b960e47784150f5a63777201ee2b15253d713e8169163a9059cbb91612e39918690600401615b61565b6020604051808303816000875af1158015612e58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e7c9190615b7a565b50805160208083015160408051918252918101859052600081830152905185926001600160a01b031691600080516020615df1833981519152919081900360600190a360068381548110612ed257612ed2615b22565b60009182526020822060039091020180546001600160a01b0319168155600181018290556002015582612f0481615baa565b935050613069565b848160200151612f1c9190615b4e565b60068481548110612f2f57612f2f615b22565b600091825260208083206001600390930201919091019290925582516001600160a01b031681526008909152604081208054879290612f6f908490615b4e565b90915550869050612f8886670de0b6b3a7640000615c66565b612f929190615c7d565b815160405163a9059cbb60e01b81529193506001600160a01b037f0000000000000000000000003b960e47784150f5a63777201ee2b15253d713e8169163a9059cbb91612fe3918690600401615b61565b6020604051808303816000875af1158015613002573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130269190615b7a565b5080516040805187815260208101859052600081830152905185926001600160a01b031691600080516020615df1833981519152919081900360600190a3600094505b50612cf4565b600491909155600554905b82156133eb5760006007838154811061309557613095615b22565b6000918252602080832060408051606081018252600390940290910180546001600160a01b031684526001810154928401839052600201549083015290925090036130ed57826130e481615baa565b9350505061307a565b8381602001511161328b5760208101516131079085615b4e565b935080602001516009600083600001516001600160a01b03166001600160a01b0316815260200190815260200160002060008282546131469190615b4e565b90915550506020810151670de0b6b3a764000090613165908890615c66565b61316f9190615c7d565b815160405163a9059cbb60e01b81529193506001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48169163a9059cbb916131c0918690600401615b61565b6020604051808303816000875af11580156131df573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132039190615b7a565b5080516020808301516040805191825291810185905285926001600160a01b031691600080516020615e11833981519152910160405180910390a36007838154811061325157613251615b22565b60009182526020822060039091020180546001600160a01b031916815560018101829055600201558261328381615baa565b9350506133e5565b83816020015161329b9190615b4e565b600784815481106132ae576132ae615b22565b600091825260208083206001600390930201919091019290925582516001600160a01b0316815260099091526040812080548692906132ee908490615b4e565b90915550670de0b6b3a764000090506133078786615c66565b6133119190615c7d565b815160405163a9059cbb60e01b81529193506001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48169163a9059cbb91613362918690600401615b61565b6020604051808303816000875af1158015613381573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133a59190615b7a565b5080516020808301516040805191825291810185905285926001600160a01b031691600080516020615e11833981519152910160405180910390a3600093505b5061307a565b50600555505050565b6133fc614985565b61340b81604001356001614cbc565b6040516370a0823160e01b81523060048201526000907f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316906370a0823190602401602060405180830381865afa158015613472573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134969190615c4d565b60405163f73e19c360e01b81528335600482015290915047906000907f0000000000000000000000003b960e47784150f5a63777201ee2b15253d713e86001600160a01b03169063f73e19c390602401602060405180830381865afa158015613503573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135279190615c4d565b90508060005b61353a6020870187615c9f565b90508110801561354a5750600082115b156138a85761355f6118656020880188615c9f565b6135a561356f6020880188615c9f565b8381811061357f5761357f615b22565b9050610140020160200160208101906135989190615a3c565b6118d76020890189615c9f565b6135b26020870187615c9f565b828181106135c2576135c2615b22565b9050610140020160800160208101906135db9190615cf0565b1561360e5760405162461bcd60e51b81526020600482015260036024820152624e313560e81b6044820152606401610329565b60408601356136206020880188615c9f565b8381811061363057613630615b22565b9050610140020160600135111561366f5760405162461bcd60e51b815260206004820152600360248201526227189b60e91b6044820152606401610329565b8161367d6020880188615c9f565b8381811061368d5761368d615b22565b905061014002016040013510156137c8576136ab6020870187615c9f565b828181106136bb576136bb615b22565b9050610140020160400135826136d19190615b4e565b91506001600160a01b037f000000000000000000000000f1b99e3e573a1a9c5e6b2ce818b617f0e664e86b166323b872dd61370f6020890189615c9f565b8481811061371f5761371f615b22565b9050610140020160200160208101906137389190615a3c565b3061374660208b018b615c9f565b8681811061375657613756615b22565b90506101400201604001356040518463ffffffff1660e01b815260040161377f93929190615bc3565b6020604051808303816000875af115801561379e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137c29190615b7a565b50613896565b6001600160a01b037f000000000000000000000000f1b99e3e573a1a9c5e6b2ce818b617f0e664e86b166323b872dd6138046020890189615c9f565b8481811061381457613814615b22565b90506101400201602001602081019061382d9190615a3c565b30856040518463ffffffff1660e01b815260040161384d93929190615bc3565b6020604051808303816000875af115801561386c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138909190615b7a565b50600091505b806138a081615baa565b91505061352d565b50604051632e1a7d4d60e01b8152853560048201527f0000000000000000000000003b960e47784150f5a63777201ee2b15253d713e86001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561390b57600080fd5b505af115801561391f573d6000803e3d6000fd5b505050507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0844761395e9190615b4e565b6040518263ffffffff1660e01b81526004016000604051808303818588803b15801561398957600080fd5b505af115801561399d573d6000803e3d6000fd5b508594506000935083925050505b6139b86020880188615c9f565b9050811080156139c85750600083115b15613be057826139db6020890189615c9f565b838181106139eb576139eb615b22565b90506101400201604001351015613a2b57613a096020880188615c9f565b82818110613a1957613a19615b22565b90506101400201604001359150613a2f565b8291505b6001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21663a9059cbb613a6b60208a018a615c9f565b84818110613a7b57613a7b615b22565b905061014002016020016020810190613a949190615a3c565b670de0b6b3a7640000613aab60408c013587615c66565b613ab59190615c7d565b6040518363ffffffff1660e01b8152600401613ad2929190615b61565b6020604051808303816000875af1158015613af1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b159190615b7a565b50613b208284615b4e565b9250613b2f6020880188615c9f565b82818110613b3f57613b3f615b22565b905061014002016020016020810190613b589190615a3c565b6001600160a01b0316613b6e6020890189615c9f565b83818110613b7e57613b7e615b22565b604080518781528c82013560208201526000818301529051610140929092029390930135927fd1d072f838d64d5c63545bc6cf88a03b39fd711611b7df5b0c0822f745044fcc925081900360600190a380613bd881615baa565b9150506139ab565b506000805460405163cce79bd560e01b81527f00000000000000000000000065d66c76447ccb45daf1e8044e918fa786a483a16001600160a01b03169163cce79bd591613ca7917f0000000000000000000000008ad599c3a0ff1de082011efddc58f1908eb6e6d8917f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2917f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4891600160a81b90910463ffffffff1690600190600401615c14565b602060405180830381865afa158015613cc4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ce89190615c4d565b6040516370a0823160e01b815230600482015290915060009087906001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216906370a0823190602401602060405180830381865afa158015613d54573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d789190615c4d565b613d829190615b4e565b9050876060013564e8d4a510006ec097ce7bc90715b34b9f1000000000600354670de0b6b3a7640000613db59190615b4e565b613dbf8686615c66565b613dc99190615c66565b613dd39190615c7d565b613ddd9190615c7d565b10613e105760405162461bcd60e51b81526020600482015260036024820152624e313760e81b6044820152606401610329565b60408051610100810182526001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2811682527f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb481660208201526000918101613e8460a08c0160808d01615d0d565b62ffffff168152602001306001600160a01b031681526020014281526020018381526020018a60600135815260200160006001600160a01b0316815250905060007f000000000000000000000000e592427a0aece92de3edee1f18e0157c058615646001600160a01b031663414bf389836040518263ffffffff1660e01b8152600401613f119190615d32565b6020604051808303816000875af1158015613f30573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f549190615c4d565b6005549091508a359060005b82156142bc57600060078381548110613f7b57613f7b615b22565b6000918252602080832060408051606081018252600390940290910180546001600160a01b03168452600181015492840183905260020154908301529092509003613fd35782613fca81615baa565b93505050613f60565b8381602001511161416a576020810151613fed9085615b4e565b935080602001516009600083600001516001600160a01b03166001600160a01b03168152602001908152602001600020600082825461402c9190615b4e565b909155505060208101518e3590614044908790615c66565b61404e9190615c7d565b815160405163a9059cbb60e01b81529193506001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48169163a9059cbb9161409f918690600401615b61565b6020604051808303816000875af11580156140be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140e29190615b7a565b5080516020808301516040805191825291810185905285926001600160a01b031691600080516020615e11833981519152910160405180910390a36007838154811061413057614130615b22565b60009182526020822060039091020180546001600160a01b031916815560018101829055600201558261416281615baa565b9350506142b6565b836007848154811061417e5761417e615b22565b9060005260206000209060030201600101600082825461419e9190615b4e565b909155505080516001600160a01b0316600090815260096020526040812080548692906141cc908490615b4e565b90915550508d356141dd8686615c66565b6141e79190615c7d565b815160405163a9059cbb60e01b81529193506001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48169163a9059cbb91614238918690600401615b61565b6020604051808303816000875af1158015614257573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061427b9190615b7a565b508051604080518681526020810185905285926001600160a01b031691600080516020615e11833981519152910160405180910390a3600093505b50613f60565b5060055550506000805460ff60a01b19169055505050505050505050565b6142e2614985565b6000805460ff600160a01b808304821615810260ff60a01b1990931692909217928390556040517fe6161233d7b23251971fb55c60874862ed7a143c115402afa8e1f2c07a131add9361433e9390049091161515815260200190565b60405180910390a1565b600054600160a01b900460ff16158061435e5750805b61438f5760405162461bcd60e51b8152602060048201526002602482015261271960f11b6044820152606401610329565b336000908152600960205260409020546143aa908390615b4e565b3360009081526009602052604090208190556002541115806143d9575033600090815260096020526040902054155b61440a5760405162461bcd60e51b8152602060048201526002602482015261271b60f11b6044820152606401610329565b336000908152600b60205260409020548290805b80156145c157336000908152600b60205260408120600790614441600185615b4e565b8154811061445157614451615b22565b90600052602060002001548154811061446c5761446c615b22565b9060005260206000209060030201905084156144c75760028101546144949062093a80615b97565b42116144c75760405162461bcd60e51b8152602060048201526002602482015261138d60f21b6044820152606401610329565b83816001015411156144f757838160010160008282546144e79190615b4e565b90915550600094506145c1915050565b60018101546145069085615b4e565b336000908152600b60205260409020909450600790614526600185615b4e565b8154811061453657614536615b22565b90600052602060002001548154811061455157614551615b22565b60009182526020808320600390920290910180546001600160a01b031916815560018101839055600201829055338252600b90526040902080548061459857614598615be7565b6001900381819060005260206000200160009055905550806145b981615bfd565b91505061441e565b5060405163a9059cbb60e01b81526001600160a01b037f0000000000000000000000003b960e47784150f5a63777201ee2b15253d713e8169063a9059cbb906146109033908890600401615b61565b6020604051808303816000875af115801561462f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146539190615b7a565b5033600081815260096020908152604091829020548251888152918201527f4f4b6ab83d39fce2cc703aa2ac1d003ccd5b4781b4a561c1c586ef2e84e4d8cb9101611532565b6146a1614985565b60018190556040518181527f2217b276de774d686f6d9419505080eeee1f2a9e95ef298c5b4266f56eb6272790602001610c1d565b6146de614985565b6001600160a01b0381166147435760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610329565b610def81614c6c565b6001548110156147835760405162461bcd60e51b81526020600482015260026024820152614e3160f01b6044820152606401610329565b6040516323b872dd60e01b81526001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4816906323b872dd906147d390339030908690600401615bc3565b6020604051808303816000875af11580156147f2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148169190615b7a565b5033600090815260086020526040902054614832908290615b97565b33600081815260086020908152604080832094909455835160608101855283815280820186815242828701908152600680546001808201835582885294517ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f600390920291820180546001600160a01b0319166001600160a01b0390921691909117905592517ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d4084015590517ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d4190920191909155938352600a9091529290209054909161491e91615b4e565b8154600181810184556000938452602090932001556006546149409190615b4e565b33600081815260086020908152604091829020548251868152918201527fcd8a16e288c9b610f6bd123e0ed3f6aa008681653a19936f37bb6b2feb17ee8f9101611097565b6000546001600160a01b03163314610e605760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610329565b6000306001600160a01b037f0000000000000000000000006e536addb53d1b47d357cdca83bcf460194a395f16148015614a3857507f000000000000000000000000000000000000000000000000000000000000000146145b15614a6257507f8589b0065033d9231159bf0ba404a710a105f42c9e5ee218d87a94049027664990565b50604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6020808301919091527f7d14230c545a7ded527e48f74a18e6313c4a04246c59f97044ce1006170eb1d6828401527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608301524660808301523060a0808401919091528351808403909101815260c0909201909252805191012090565b60007fc8aea8e60353611f3ed5409dad2d3173390bd252431198e7300eda67fefb66b1826000015183602001518460400151856060015186608001518760a001518860c00151604051602001614b9f98979695949392919097885260208801969096526001600160a01b0394909416604087015260608601929092526080850152151560a084015260c083015260e08201526101000190565b6040516020818303038152906040528051906020012090506000614bc282615456565b90506000614be0828560e001518661010001518761012001516154a4565b905083602001516001600160a01b0316816001600160a01b031614614c2c5760405162461bcd60e51b81526020600482015260026024820152614e3960f01b6044820152606401610329565b428460a001511015614c665760405162461bcd60e51b815260206004820152600360248201526204e31360ec1b6044820152606401610329565b50505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000805460405163cce79bd560e01b81527f00000000000000000000000065d66c76447ccb45daf1e8044e918fa786a483a16001600160a01b03169163cce79bd591614d82917f00000000000000000000000082c427adfdf2d245ec51d8046b41c4ee87f0d29c917f000000000000000000000000f1b99e3e573a1a9c5e6b2ce818b617f0e664e86b917f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc291600160a81b90910463ffffffff1690600190600401615c14565b602060405180830381865afa158015614d9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614dc39190615c4d565b90508115614e3857670de0b6b3a7640000600354670de0b6b3a7640000614dea9190615b97565b614df49083615c66565b614dfe9190615c7d565b831115614e335760405162461bcd60e51b81526020600482015260036024820152624e323160e81b6044820152606401610329565b505050565b670de0b6b3a7640000600354670de0b6b3a7640000614e579190615b4e565b614e619083615c66565b614e6b9190615c7d565b831015614e335760405162461bcd60e51b815260206004820152600360248201526227191960e91b6044820152606401610329565b600080614eab6154cc565b90506000807f0000000000000000000000003b960e47784150f5a63777201ee2b15253d713e86001600160a01b031663533092ef6040518163ffffffff1660e01b8152600401608060405180830381865afa158015614f0e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614f329190615d9b565b9350935050506000670de0b6b3a76400008483614f4f9190615c66565b614f599190615c7d565b614f639084615b97565b614f6d8388615c66565b614f779190615c7d565b9695505050505050565b6001600160a01b0382166000908152600c6020908152604080832084845290915290205460ff1615614fdb5760405162461bcd60e51b815260206004820152600360248201526204e32360ec1b6044820152606401610329565b6001600160a01b039091166000908152600c6020908152604080832093835292905220805460ff19166001179055565b6000805460405163cce79bd560e01b81527f00000000000000000000000065d66c76447ccb45daf1e8044e918fa786a483a16001600160a01b03169163cce79bd5916150d1917f00000000000000000000000082c427adfdf2d245ec51d8046b41c4ee87f0d29c917f000000000000000000000000f1b99e3e573a1a9c5e6b2ce818b617f0e664e86b917f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc291600160a81b90910463ffffffff1690600190600401615c14565b602060405180830381865afa1580156150ee573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906151129190615c4d565b905060007f00000000000000000000000065d66c76447ccb45daf1e8044e918fa786a483a16001600160a01b031663cce79bd57f0000000000000000000000008ad599c3a0ff1de082011efddc58f1908eb6e6d87f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc27f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48600060159054906101000a900463ffffffff1660016040518663ffffffff1660e01b81526004016151dd959493929190615c14565b602060405180830381865afa1580156151fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061521e9190615c4d565b90506000807f0000000000000000000000003b960e47784150f5a63777201ee2b15253d713e86001600160a01b031663533092ef6040518163ffffffff1660e01b8152600401608060405180830381865afa158015615281573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906152a59190615d9b565b93509350505060007f0000000000000000000000003b960e47784150f5a63777201ee2b15253d713e86001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561530b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061532f9190615c4d565b84670de0b6b3a76400006153438886615c66565b61534d9190615c7d565b6153579086615b4e565b6153619190615c66565b61536b9190615c7d565b905061537c64e8d4a5100082615c7d565b9050670de0b6b3a7640000600354670de0b6b3a764000061539d9190615b97565b6153a79083615c66565b6153b19190615c7d565b8611156153e65760405162461bcd60e51b81526020600482015260036024820152624e323360e81b6044820152606401610329565b670de0b6b3a7640000600354670de0b6b3a76400006154059190615b4e565b61540f9083615c66565b6154199190615c7d565b86101561544e5760405162461bcd60e51b8152602060048201526003602482015262138c8d60ea1b6044820152606401610329565b505050505050565b6000610e486154636149df565b8360405161190160f01b6020820152602281018390526042810182905260009060620160405160208183030381529060405280519060200120905092915050565b60008060006154b58787878761569c565b915091506154c281615760565b5095945050505050565b6000807f00000000000000000000000064187ae08781b09368e6253f9e94951243a493d56001600160a01b031663978bbdb96040518163ffffffff1660e01b8152600401602060405180830381865afa15801561552d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906155519190615c4d565b90508060000361556357600091505090565b60405163cce79bd560e01b81526000906001600160a01b037f00000000000000000000000065d66c76447ccb45daf1e8044e918fa786a483a1169063cce79bd59061563b907f00000000000000000000000082c427adfdf2d245ec51d8046b41c4ee87f0d29c907f000000000000000000000000f1b99e3e573a1a9c5e6b2ce818b617f0e664e86b907f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2907f00000000000000000000000000000000000000000000000000000000000001a490600190600401615c14565b602060405180830381865afa158015615658573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061567c9190615c4d565b905061271061568b8383615c66565b6156959190615c7d565b9250505090565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156156d35750600090506003615757565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015615727573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811661575057600060019250925050615757565b9150600090505b94509492505050565b600081600481111561577457615774615dda565b0361577c5750565b600181600481111561579057615790615dda565b036157dd5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610329565b60028160048111156157f1576157f1615dda565b0361583e5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610329565b600381600481111561585257615852615dda565b03610def5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610329565b6000602082840312156158bc57600080fd5b5035919050565b6000602082840312156158d557600080fd5b813563ffffffff811681146158e957600080fd5b9392505050565b6001600160a01b0381168114610def57600080fd5b8035615910816158f0565b919050565b6000806040838503121561592857600080fd5b8235615933816158f0565b946020939093013593505050565b604051610140810167ffffffffffffffff8111828210171561597357634e487b7160e01b600052604160045260246000fd5b60405290565b8015158114610def57600080fd5b803561591081615979565b803560ff8116811461591057600080fd5b600061014082840312156159b657600080fd5b6159be615941565b823581526159ce60208401615905565b602082015260408301356040820152606083013560608201526159f360808401615987565b608082015260a083013560a082015260c083013560c0820152615a1860e08401615992565b60e08201526101008381013590820152610120928301359281019290925250919050565b600060208284031215615a4e57600080fd5b81356158e9816158f0565b60008060408385031215615a6c57600080fd5b823591506020830135615a7e81615979565b809150509250929050565b600060208284031215615a9b57600080fd5b813567ffffffffffffffff811115615ab257600080fd5b820161010081850312156158e957600080fd5b60008060408385031215615ad857600080fd5b50508035926020909101359150565b600060208284031215615af957600080fd5b813567ffffffffffffffff811115615b1057600080fd5b820160a081850312156158e957600080fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b81810381811115610e4857610e48615b38565b6001600160a01b03929092168252602082015260400190565b600060208284031215615b8c57600080fd5b81516158e981615979565b80820180821115610e4857610e48615b38565b600060018201615bbc57615bbc615b38565b5060010190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b634e487b7160e01b600052603160045260246000fd5b600081615c0c57615c0c615b38565b506000190190565b6001600160a01b039586168152938516602085015291909316604083015263ffffffff9092166060820152901515608082015260a00190565b600060208284031215615c5f57600080fd5b5051919050565b8082028115828204841417610e4857610e48615b38565b600082615c9a57634e487b7160e01b600052601260045260246000fd5b500490565b6000808335601e19843603018112615cb657600080fd5b83018035915067ffffffffffffffff821115615cd157600080fd5b602001915061014081023603821315615ce957600080fd5b9250929050565b600060208284031215615d0257600080fd5b81356158e981615979565b600060208284031215615d1f57600080fd5b813562ffffff811681146158e957600080fd5b81516001600160a01b03908116825260208084015182169083015260408084015162ffffff16908301526060808401518216908301526080808401519083015260a0838101519083015260c0808401519083015260e09283015116918101919091526101000190565b60008060008060808587031215615db157600080fd5b8451615dbc816158f0565b60208601516040870151606090970151919890975090945092505050565b634e487b7160e01b600052602160045260246000fdfef407c5a0c99a9a3d15fe5a46a4aba5ce747e855b58bc1aec4a589fd53bda599e460140ba175e3953a9d581c92fd2fc50c428691b4220431ff4a3f08c62aa3906a2646970667358221220851c03f17b6117b7277341d79c60c79cc765d347623650558859db49b5afd68d64736f6c63430008110033

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

0000000000000000000000003b960e47784150f5a63777201ee2b15253d713e8000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564

-----Decoded View---------------
Arg [0] : _crab (address): 0x3B960E47784150F5a63777201ee2B15253D713e8
Arg [1] : _swapRouter (address): 0xE592427A0AEce92De3Edee1F18E0157C05861564

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000003b960e47784150f5a63777201ee2b15253d713e8
Arg [1] : 000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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