ETH Price: $1,787.39 (+12.87%)

Contract

0x94Ea0183A3268635E34332A76DD2e9Eff13A00f4
 
Transaction Hash
Method
Block
From
To
Sell Base Tokens...181375422025-04-19 17:48:193 days ago1745084899IN
0x94Ea0183...ff13A00f4
0 ETH0.00000020.00078107
Remove Liquidity...179962972025-04-16 11:20:096 days ago1744802409IN
0x94Ea0183...ff13A00f4
0 ETH0.000000380.00114314
Sell Base Tokens...179405142025-04-15 4:20:438 days ago1744690843IN
0x94Ea0183...ff13A00f4
0 ETH0.000001390.0062
Remove Liquidity179394112025-04-15 3:43:578 days ago1744688637IN
0x94Ea0183...ff13A00f4
0 ETH0.000001260.00615008
Remove Liquidity179391882025-04-15 3:36:318 days ago1744688191IN
0x94Ea0183...ff13A00f4
0 ETH0.000001260.00616498
Sell Base Tokens...179312642025-04-14 23:12:238 days ago1744672343IN
0x94Ea0183...ff13A00f4
0 ETH0.000000520.00231695
Remove Liquidity179312332025-04-14 23:11:218 days ago1744672281IN
0x94Ea0183...ff13A00f4
0 ETH0.000000380.00230277
Sell Base Tokens...179055592025-04-14 8:55:338 days ago1744620933IN
0x94Ea0183...ff13A00f4
0 ETH0.000000450.00208
Remove Liquidity179055422025-04-14 8:54:598 days ago1744620899IN
0x94Ea0183...ff13A00f4
0 ETH0.000000420.00207981
Sell Quote Token...177461892025-04-10 16:23:1312 days ago1744302193IN
0x94Ea0183...ff13A00f4
0 ETH0.000000340.00177774
Sell Quote Token...177087132025-04-09 19:34:0113 days ago1744227241IN
0x94Ea0183...ff13A00f4
0 ETH0.000000170.00086991
Sell Base Tokens...177061462025-04-09 18:08:2713 days ago1744222107IN
0x94Ea0183...ff13A00f4
0 ETH0.000001510.0058337
Remove Liquidity...176605382025-04-08 16:48:1114 days ago1744130891IN
0x94Ea0183...ff13A00f4
0 ETH0.00000030.00098651
Sell Quote Token...174404572025-04-03 14:32:0919 days ago1743690729IN
0x94Ea0183...ff13A00f4
0 ETH0.000000260.00143234
Sell Quote Token...174403932025-04-03 14:30:0119 days ago1743690601IN
0x94Ea0183...ff13A00f4
0 ETH0.000000260.0014245
Sell Base Tokens...174159132025-04-03 0:54:0120 days ago1743641641IN
0x94Ea0183...ff13A00f4
0 ETH0.000000040.00017955
Remove Liquidity174156982025-04-03 0:46:5120 days ago1743641211IN
0x94Ea0183...ff13A00f4
0 ETH0.000000020.00013889
Remove Liquidity...173906942025-04-02 10:53:2320 days ago1743591203IN
0x94Ea0183...ff13A00f4
0 ETH0.000000060.00018259
Sell Quote Token...173134132025-03-31 15:57:2122 days ago1743436641IN
0x94Ea0183...ff13A00f4
0 ETH0.000000030.00020129
Remove Liquidity173131522025-03-31 15:48:3922 days ago1743436119IN
0x94Ea0183...ff13A00f4
0 ETH0.000000020.00016595
Sell Quote Token...171843852025-03-28 16:16:2525 days ago1743178585IN
0x94Ea0183...ff13A00f4
0 ETH0.000000220.00122937
Sell Quote Token...171843732025-03-28 16:16:0125 days ago1743178561IN
0x94Ea0183...ff13A00f4
0 ETH0.000000250.00122975
Sell Quote Token...171728372025-03-28 9:51:2925 days ago1743155489IN
0x94Ea0183...ff13A00f4
0 ETH0.000000250.00129013
Sell Quote Token...171281432025-03-27 9:01:4126 days ago1743066101IN
0x94Ea0183...ff13A00f4
0 ETH0.000000230.00130155
Remove Liquidity171279412025-03-27 8:54:5726 days ago1743065697IN
0x94Ea0183...ff13A00f4
0 ETH0.000000210.00130118
View all transactions

Parent Transaction Hash Block From To
View All Internal Transactions

Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
BlastMIMSwapRouter

Compiler Version
v0.8.20+commit.a1b79de6

Optimization Enabled:
Yes with 400 runs

Other Settings:
paris EvmVersion
File 1 of 17 : BlastMIMSwapRouter.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.0;

import {BlastYields} from "/blast/libraries/BlastYields.sol";
import {Router} from "/mimswap/periphery/Router.sol";
import {IWETH} from "interfaces/IWETH.sol";
import {IFactory} from "/mimswap/interfaces/IFactory.sol";

contract BlastMIMSwapRouter is Router {
    constructor(IWETH weth_, IFactory factory, address governor_) Router(weth_, factory) {
        if (governor_ == address(0)) {
            revert ErrZeroAddress();
        }
        BlastYields.configureDefaultClaimables(governor_);
    }
}

File 2 of 17 : BlastYields.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.0;

import {IBlast, IERC20Rebasing, YieldMode, GasMode} from "interfaces/IBlast.sol";
import {Address} from "openzeppelin-contracts/utils/Address.sol";

library BlastYields {
    event LogBlastGasClaimed(address indexed recipient, uint256 amount);
    event LogBlastETHClaimed(address indexed recipient, uint256 amount);
    event LogBlastTokenClaimed(address indexed recipient, address indexed token, uint256 amount);
    event LogBlastTokenClaimableEnabled(address indexed contractAddress, address indexed token);
    event LogBlastNativeClaimableEnabled(address indexed contractAddress);

    IBlast constant BLAST_YIELD_PRECOMPILE = IBlast(0x4300000000000000000000000000000000000002);

    //////////////////////////////////////////////////////////////////////////////////////
    // CONFIGURATION
    //////////////////////////////////////////////////////////////////////////////////////

    function enableTokenClaimable(address token) internal {
        if (IERC20Rebasing(token).getConfiguration(address(this)) == YieldMode.CLAIMABLE) {
            return;
        }

        IERC20Rebasing(token).configure(YieldMode.CLAIMABLE);
        emit LogBlastTokenClaimableEnabled(address(this), token);
    }

    function configureDefaultClaimables(address governor_) internal {
        BLAST_YIELD_PRECOMPILE.configure(YieldMode.CLAIMABLE, GasMode.CLAIMABLE, governor_);
        emit LogBlastNativeClaimableEnabled(address(this));
    }

    //////////////////////////////////////////////////////////////////////////////////////
    // GAS CLAIMING
    //////////////////////////////////////////////////////////////////////////////////////
    
    function claimMaxGasYields(address recipient) internal returns (uint256) {
        return claimMaxGasYields(address(this), recipient);
    }

    function claimMaxGasYields(address contractAddress, address recipient) internal returns (uint256 amount) {
        amount = BLAST_YIELD_PRECOMPILE.claimMaxGas(contractAddress, recipient);
        emit LogBlastGasClaimed(recipient, amount);
    }

    //////////////////////////////////////////////////////////////////////////////////////
    // NATIVE CLAIMING
    //////////////////////////////////////////////////////////////////////////////////////<

    function claimAllNativeYields(address recipient) internal returns (uint256 amount) {
        return claimAllNativeYields(address(this), recipient);
    }

    function claimAllNativeYields(address contractAddress, address recipient) internal returns (uint256 amount) {
        amount = BLAST_YIELD_PRECOMPILE.claimAllYield(contractAddress, recipient);
        emit LogBlastETHClaimed(recipient, amount);
    }

    function claimNativeYields(address contractAddress, uint256 amount, address recipient) internal returns (uint256) {
        amount = BLAST_YIELD_PRECOMPILE.claimYield(contractAddress, recipient, amount);
        emit LogBlastETHClaimed(recipient, amount);
        return amount;
    }

    //////////////////////////////////////////////////////////////////////////////////////
    // TOKENS CLAIMING
    //////////////////////////////////////////////////////////////////////////////////////

    function claimAllTokenYields(address token, address recipient) internal returns (uint256 amount) {
        amount = IERC20Rebasing(token).claim(recipient, IERC20Rebasing(token).getClaimableAmount(address(this)));
        emit LogBlastTokenClaimed(recipient, address(token), amount);
    }

    function claimTokenYields(address token, uint256 amount, address recipient) internal returns (uint256) {
        amount = IERC20Rebasing(token).claim(recipient, amount);
        emit LogBlastTokenClaimed(recipient, address(token), amount);
        return amount;
    }

    //////////////////////////////////////////////////////////////////////////////////////
    // ARBITRARY PRECOMPILE CALLS
    // Meant to be used for any other calls to the precompile not covered by the above
    //////////////////////////////////////////////////////////////////////////////////////

    function callPrecompile(bytes calldata data) internal {
        Address.functionCall(address(BLAST_YIELD_PRECOMPILE), data);
    }
}

File 3 of 17 : Router.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.0;

import {SafeTransferLib} from "solady/utils/SafeTransferLib.sol";
import {IERC20} from "openzeppelin-contracts/interfaces/IERC20.sol";
import {Math} from "/mimswap/libraries/Math.sol";
import {DecimalMath} from "/mimswap/libraries/DecimalMath.sol";
import {IWETH} from "interfaces/IWETH.sol";
import {IMagicLP} from "/mimswap/interfaces/IMagicLP.sol";
import {IFactory} from "/mimswap/interfaces/IFactory.sol";
import {IERC20Metadata} from "openzeppelin-contracts/interfaces/IERC20Metadata.sol";
import {ReentrancyGuard} from "solady/utils/ReentrancyGuard.sol";

struct AddLiquidityImbalancedParams {
    address lp;
    address to;
    uint256 baseInAmount;
    uint256 quoteInAmount;
    bool remainingAmountToSwapIsBase;
    uint256 remainingAmountToSwap;
    uint256 minimumShares;
    uint256 deadline;
}

/// @notice Router for creating and interacting with MagicLP
/// Can only be used for pool created by the Factory
///
/// @dev A pool can be removed from the Factory. So, when integrating with this contract,
/// validate that the pool exists using the Factory `poolExists` function.
contract Router is ReentrancyGuard {
    using SafeTransferLib for address;
    using SafeTransferLib for address payable;

    error ErrNotETHLP();
    error ErrExpired();
    error ErrZeroAddress();
    error ErrPathTooLong();
    error ErrEmptyPath();
    error ErrBadPath();
    error ErrTooHighSlippage(uint256 amountOut);
    error ErrInvalidBaseToken();
    error ErrInvalidQuoteToken();
    error ErrInTokenNotETH();
    error ErrOutTokenNotETH();
    error ErrInvalidQuoteTarget();
    error ErrZeroDecimals();
    error ErrTooLargeDecimals();
    error ErrDecimalsDifferenceTooLarge();
    error ErrUnknownPool();

    uint256 public constant MAX_BASE_QUOTE_DECIMALS_DIFFERENCE = 12;

    IWETH public immutable weth;
    IFactory public immutable factory;

    receive() external payable {}

    constructor(IWETH weth_, IFactory factory_) {
        if (address(weth_) == address(0) || address(factory_) == address(0)) {
            revert ErrZeroAddress();
        }

        weth = weth_;
        factory = factory_;
    }

    modifier ensureDeadline(uint256 deadline) {
        if (block.timestamp > deadline) {
            revert ErrExpired();
        }
        _;
    }

    modifier onlyKnownPool(address pool) {
        if (!factory.poolExists(pool)) {
            revert ErrUnknownPool();
        }
        _;
    }

    function createPool(
        address baseToken,
        address quoteToken,
        uint256 lpFeeRate,
        uint256 i,
        uint256 k,
        address to,
        uint256 baseInAmount,
        uint256 quoteInAmount,
        bool protocolOwnedPool
    ) public virtual returns (address clone, uint256 shares) {
        _validateDecimals(IERC20Metadata(baseToken).decimals(), IERC20Metadata(quoteToken).decimals());

        clone = IFactory(factory).create(baseToken, quoteToken, lpFeeRate, i, k, protocolOwnedPool);

        baseToken.safeTransferFrom(msg.sender, clone, baseInAmount);
        quoteToken.safeTransferFrom(msg.sender, clone, quoteInAmount);
        (shares, , ) = IMagicLP(clone).buyShares(to);
    }

    function createPoolETH(
        address token,
        bool useTokenAsQuote,
        uint256 lpFeeRate,
        uint256 i,
        uint256 k,
        address to,
        uint256 tokenInAmount,
        bool protocolOwnedPool
    ) public payable virtual returns (address clone, uint256 shares) {
        if (useTokenAsQuote) {
            _validateDecimals(18, IERC20Metadata(token).decimals());
        } else {
            _validateDecimals(IERC20Metadata(token).decimals(), 18);
        }

        clone = IFactory(factory).create(
            useTokenAsQuote ? address(weth) : token,
            useTokenAsQuote ? token : address(weth),
            lpFeeRate,
            i,
            k,
            protocolOwnedPool
        );

        weth.deposit{value: msg.value}();
        token.safeTransferFrom(msg.sender, clone, tokenInAmount);
        address(weth).safeTransfer(clone, msg.value);
        (shares, , ) = IMagicLP(clone).buyShares(to);
    }

    function previewCreatePool(
        uint256 i,
        uint256 baseInAmount,
        uint256 quoteInAmount
    ) external pure returns (uint256 baseAdjustedInAmount, uint256 quoteAdjustedInAmount, uint256 shares) {
        shares = quoteInAmount < DecimalMath.mulFloor(baseInAmount, i) ? DecimalMath.divFloor(quoteInAmount, i) : baseInAmount;
        baseAdjustedInAmount = shares;
        quoteAdjustedInAmount = DecimalMath.mulFloor(shares, i);

        if (shares <= 2001) {
            return (0, 0, 0);
        }

        shares -= 1001;
    }

    function addLiquidity(
        address lp,
        address to,
        uint256 baseInAmount,
        uint256 quoteInAmount,
        uint256 minimumShares,
        uint256 deadline
    )
        public
        virtual
        ensureDeadline(deadline)
        onlyKnownPool(lp)
        returns (uint256 baseAdjustedInAmount, uint256 quoteAdjustedInAmount, uint256 shares)
    {
        (baseAdjustedInAmount, quoteAdjustedInAmount) = _adjustAddLiquidity(lp, baseInAmount, quoteInAmount);

        IMagicLP(lp)._BASE_TOKEN_().safeTransferFrom(msg.sender, lp, baseAdjustedInAmount);
        IMagicLP(lp)._QUOTE_TOKEN_().safeTransferFrom(msg.sender, lp, quoteAdjustedInAmount);

        shares = _addLiquidity(lp, to, minimumShares);
    }

    function addLiquidityUnsafe(
        address lp,
        address to,
        uint256 baseInAmount,
        uint256 quoteInAmount,
        uint256 minimumShares,
        uint256 deadline
    ) public virtual ensureDeadline(deadline) onlyKnownPool(lp) returns (uint256 shares) {
        IMagicLP(lp)._BASE_TOKEN_().safeTransferFrom(msg.sender, lp, baseInAmount);
        IMagicLP(lp)._QUOTE_TOKEN_().safeTransferFrom(msg.sender, lp, quoteInAmount);

        return _addLiquidity(lp, to, minimumShares);
    }

    function addLiquidityETH(
        address lp,
        address to,
        address payable refundTo,
        uint256 tokenInAmount,
        uint256 minimumShares,
        uint256 deadline
    )
        public
        payable
        virtual
        nonReentrant
        ensureDeadline(deadline)
        onlyKnownPool(lp)
        returns (uint256 baseAdjustedInAmount, uint256 quoteAdjustedInAmount, uint256 shares)
    {
        uint256 wethAdjustedAmount;
        uint256 tokenAdjustedAmount;
        address token = IMagicLP(lp)._BASE_TOKEN_();
        if (token == address(weth)) {
            token = IMagicLP(lp)._QUOTE_TOKEN_();
            (baseAdjustedInAmount, quoteAdjustedInAmount) = _adjustAddLiquidity(lp, msg.value, tokenInAmount);
            wethAdjustedAmount = baseAdjustedInAmount;
            tokenAdjustedAmount = quoteAdjustedInAmount;
        } else if (IMagicLP(lp)._QUOTE_TOKEN_() == address(weth)) {
            (baseAdjustedInAmount, quoteAdjustedInAmount) = _adjustAddLiquidity(lp, tokenInAmount, msg.value);
            wethAdjustedAmount = quoteAdjustedInAmount;
            tokenAdjustedAmount = baseAdjustedInAmount;
        } else {
            revert ErrNotETHLP();
        }

        weth.deposit{value: wethAdjustedAmount}();
        address(weth).safeTransfer(lp, wethAdjustedAmount);

        // Refund unused ETH
        if (msg.value > wethAdjustedAmount) {
            refundTo.safeTransferETH(msg.value - wethAdjustedAmount);
        }

        token.safeTransferFrom(msg.sender, lp, tokenAdjustedAmount);

        shares = _addLiquidity(lp, to, minimumShares);
    }

    function addLiquidityETHUnsafe(
        address lp,
        address to,
        uint256 tokenInAmount,
        uint256 minimumShares,
        uint256 deadline
    ) public payable virtual ensureDeadline(deadline) onlyKnownPool(lp) returns (uint256 shares) {
        address token = IMagicLP(lp)._BASE_TOKEN_();
        if (token == address(weth)) {
            token = IMagicLP(lp)._QUOTE_TOKEN_();
        } else if (IMagicLP(lp)._QUOTE_TOKEN_() != address(weth)) {
            revert ErrNotETHLP();
        }

        weth.deposit{value: msg.value}();
        address(weth).safeTransfer(lp, msg.value);

        token.safeTransferFrom(msg.sender, lp, tokenInAmount);

        return _addLiquidity(lp, to, minimumShares);
    }

    function previewRemoveLiquidity(
        address lp,
        uint256 sharesIn
    ) external view nonReadReentrant onlyKnownPool(lp) returns (uint256 baseAmountOut, uint256 quoteAmountOut) {
        uint256 baseBalance = IMagicLP(lp)._BASE_TOKEN_().balanceOf(address(lp));
        uint256 quoteBalance = IMagicLP(lp)._QUOTE_TOKEN_().balanceOf(address(lp));

        uint256 totalShares = IERC20(lp).totalSupply();

        baseAmountOut = (baseBalance * sharesIn) / totalShares;
        quoteAmountOut = (quoteBalance * sharesIn) / totalShares;
    }

    function removeLiquidity(
        address lp,
        address to,
        uint256 sharesIn,
        uint256 minimumBaseAmount,
        uint256 minimumQuoteAmount,
        uint256 deadline
    ) public virtual onlyKnownPool(lp) returns (uint256 baseAmountOut, uint256 quoteAmountOut) {
        lp.safeTransferFrom(msg.sender, address(this), sharesIn);

        return IMagicLP(lp).sellShares(sharesIn, to, minimumBaseAmount, minimumQuoteAmount, "", deadline);
    }

    function removeLiquidityETH(
        address lp,
        address to,
        uint256 sharesIn,
        uint256 minimumETHAmount,
        uint256 minimumTokenAmount,
        uint256 deadline
    ) public virtual onlyKnownPool(lp) returns (uint256 ethAmountOut, uint256 tokenAmountOut) {
        lp.safeTransferFrom(msg.sender, address(this), sharesIn);

        address token = IMagicLP(lp)._BASE_TOKEN_();
        if (token == address(weth)) {
            token = IMagicLP(lp)._QUOTE_TOKEN_();
            (ethAmountOut, tokenAmountOut) = IMagicLP(lp).sellShares(
                sharesIn,
                address(this),
                minimumETHAmount,
                minimumTokenAmount,
                "",
                deadline
            );
        } else if (IMagicLP(lp)._QUOTE_TOKEN_() == address(weth)) {
            (tokenAmountOut, ethAmountOut) = IMagicLP(lp).sellShares(
                sharesIn,
                address(this),
                minimumTokenAmount,
                minimumETHAmount,
                "",
                deadline
            );
        } else {
            revert ErrNotETHLP();
        }

        weth.withdraw(ethAmountOut);
        to.safeTransferETH(ethAmountOut);

        token.safeTransfer(to, tokenAmountOut);
    }

    function swapTokensForTokens(
        address to,
        uint256 amountIn,
        address[] calldata path,
        uint256 directions,
        uint256 minimumOut,
        uint256 deadline
    ) public virtual ensureDeadline(deadline) returns (uint256 amountOut) {
        _validatePath(path);

        address firstLp = path[0];

        // Transfer to the first LP
        if (directions & 1 == 0) {
            IMagicLP(firstLp)._BASE_TOKEN_().safeTransferFrom(msg.sender, address(firstLp), amountIn);
        } else {
            IMagicLP(firstLp)._QUOTE_TOKEN_().safeTransferFrom(msg.sender, address(firstLp), amountIn);
        }

        return _swap(to, path, directions, minimumOut);
    }

    function swapETHForTokens(
        address to,
        address[] calldata path,
        uint256 directions,
        uint256 minimumOut,
        uint256 deadline
    ) public payable virtual ensureDeadline(deadline) returns (uint256 amountOut) {
        _validatePath(path);

        address firstLp = path[0];
        address inToken;

        if (directions & 1 == 0) {
            inToken = IMagicLP(firstLp)._BASE_TOKEN_();
        } else {
            inToken = IMagicLP(firstLp)._QUOTE_TOKEN_();
        }

        // Transfer to the first LP
        if (inToken != address(weth)) {
            revert ErrInTokenNotETH();
        }

        weth.deposit{value: msg.value}();
        inToken.safeTransfer(address(firstLp), msg.value);

        return _swap(to, path, directions, minimumOut);
    }

    function swapTokensForETH(
        address to,
        uint256 amountIn,
        address[] calldata path,
        uint256 directions,
        uint256 minimumOut,
        uint256 deadline
    ) public virtual ensureDeadline(deadline) returns (uint256 amountOut) {
        _validatePath(path);

        uint256 lastLpIndex = path.length - 1;
        address lastLp = path[lastLpIndex];
        address outToken;

        if ((directions >> lastLpIndex) & 1 == 0) {
            outToken = IMagicLP(lastLp)._QUOTE_TOKEN_();
        } else {
            outToken = IMagicLP(lastLp)._BASE_TOKEN_();
        }

        if (outToken != address(weth)) {
            revert ErrOutTokenNotETH();
        }

        address firstLp = path[0];

        // Transfer to the first LP
        if (directions & 1 == 0) {
            IMagicLP(firstLp)._BASE_TOKEN_().safeTransferFrom(msg.sender, firstLp, amountIn);
        } else {
            IMagicLP(firstLp)._QUOTE_TOKEN_().safeTransferFrom(msg.sender, firstLp, amountIn);
        }

        amountOut = _swap(address(this), path, directions, minimumOut);
        weth.withdraw(amountOut);

        to.safeTransferETH(amountOut);
    }

    function sellBaseTokensForTokens(
        address lp,
        address to,
        uint256 amountIn,
        uint256 minimumOut,
        uint256 deadline
    ) public virtual ensureDeadline(deadline) onlyKnownPool(lp) returns (uint256 amountOut) {
        IMagicLP(lp)._BASE_TOKEN_().safeTransferFrom(msg.sender, lp, amountIn);
        return _sellBase(lp, to, minimumOut);
    }

    function sellBaseETHForTokens(
        address lp,
        address to,
        uint256 minimumOut,
        uint256 deadline
    ) public payable virtual ensureDeadline(deadline) onlyKnownPool(lp) returns (uint256 amountOut) {
        address baseToken = IMagicLP(lp)._BASE_TOKEN_();

        if (baseToken != address(weth)) {
            revert ErrInvalidBaseToken();
        }

        weth.deposit{value: msg.value}();
        baseToken.safeTransfer(lp, msg.value);
        return _sellBase(lp, to, minimumOut);
    }

    function sellBaseTokensForETH(
        address lp,
        address to,
        uint256 amountIn,
        uint256 minimumOut,
        uint256 deadline
    ) public virtual ensureDeadline(deadline) onlyKnownPool(lp) returns (uint256 amountOut) {
        if (IMagicLP(lp)._QUOTE_TOKEN_() != address(weth)) {
            revert ErrInvalidQuoteToken();
        }

        IMagicLP(lp)._BASE_TOKEN_().safeTransferFrom(msg.sender, lp, amountIn);
        amountOut = _sellBase(lp, address(this), minimumOut);
        weth.withdraw(amountOut);
        to.safeTransferETH(amountOut);
    }

    function sellQuoteTokensForTokens(
        address lp,
        address to,
        uint256 amountIn,
        uint256 minimumOut,
        uint256 deadline
    ) public virtual ensureDeadline(deadline) onlyKnownPool(lp) returns (uint256 amountOut) {
        IMagicLP(lp)._QUOTE_TOKEN_().safeTransferFrom(msg.sender, lp, amountIn);

        return _sellQuote(lp, to, minimumOut);
    }

    function sellQuoteETHForTokens(
        address lp,
        address to,
        uint256 minimumOut,
        uint256 deadline
    ) public payable virtual ensureDeadline(deadline) onlyKnownPool(lp) returns (uint256 amountOut) {
        address quoteToken = IMagicLP(lp)._QUOTE_TOKEN_();

        if (quoteToken != address(weth)) {
            revert ErrInvalidQuoteToken();
        }

        weth.deposit{value: msg.value}();
        quoteToken.safeTransfer(lp, msg.value);
        return _sellQuote(lp, to, minimumOut);
    }

    function sellQuoteTokensForETH(
        address lp,
        address to,
        uint256 amountIn,
        uint256 minimumOut,
        uint256 deadline
    ) public virtual ensureDeadline(deadline) onlyKnownPool(lp) returns (uint256 amountOut) {
        if (IMagicLP(lp)._BASE_TOKEN_() != address(weth)) {
            revert ErrInvalidBaseToken();
        }

        IMagicLP(lp)._QUOTE_TOKEN_().safeTransferFrom(msg.sender, lp, amountIn);
        amountOut = _sellQuote(lp, address(this), minimumOut);
        weth.withdraw(amountOut);
        to.safeTransferETH(amountOut);
    }

    function addLiquidityOneSide(
        address lp,
        address to,
        bool inAmountIsBase,
        uint256 inAmount,
        uint256 inAmountToSwap,
        uint256 minimumShares,
        uint256 deadline
    ) public virtual ensureDeadline(deadline) onlyKnownPool(lp) returns (uint256 baseAmount, uint256 quoteAmount, uint256 shares) {
        address baseToken = IMagicLP(lp)._BASE_TOKEN_();
        address quoteToken = IMagicLP(lp)._QUOTE_TOKEN_();

        // base -> quote
        if (inAmountIsBase) {
            baseToken.safeTransferFrom(msg.sender, address(this), inAmount);
            baseAmount = inAmount - inAmountToSwap;
            baseToken.safeTransfer(lp, inAmountToSwap);
            quoteAmount = IMagicLP(lp).sellBase(address(this));
        }
        // quote -> base
        else {
            quoteToken.safeTransferFrom(msg.sender, address(this), inAmount);
            quoteAmount = inAmount - inAmountToSwap;
            quoteToken.safeTransfer(lp, inAmountToSwap);
            baseAmount = IMagicLP(lp).sellQuote(address(this));
        }

        (baseAmount, quoteAmount) = _adjustAddLiquidity(lp, baseAmount, quoteAmount);
        baseToken.safeTransfer(lp, baseAmount);
        quoteToken.safeTransfer(lp, quoteAmount);
        shares = _addLiquidity(lp, to, minimumShares);

        // Refund remaining tokens
        uint256 remaining = baseToken.balanceOf(address(this));
        if (remaining > 0) {
            baseToken.safeTransfer(msg.sender, remaining);
        }

        remaining = quoteToken.balanceOf(address(this));
        if (remaining > 0) {
            quoteToken.safeTransfer(msg.sender, remaining);
        }
    }

    function removeLiquidityOneSide(
        address lp,
        address to,
        bool withdrawBase,
        uint256 sharesIn,
        uint256 minAmountOut,
        uint256 deadline
    ) public virtual ensureDeadline(deadline) onlyKnownPool(lp) returns (uint256 amountOut) {
        address baseToken = IMagicLP(lp)._BASE_TOKEN_();
        address quoteToken = IMagicLP(lp)._QUOTE_TOKEN_();

        lp.safeTransferFrom(msg.sender, address(this), sharesIn);
        (uint256 baseAmount, uint256 quoteAmount) = IMagicLP(lp).sellShares(sharesIn, address(this), 0, 0, "", deadline);

        // withdraw base
        if (withdrawBase) {
            quoteToken.safeTransfer(lp, quoteAmount);
            amountOut = baseAmount + IMagicLP(lp).sellQuote(address(this));

            if (amountOut > 0) {
                baseToken.safeTransfer(to, amountOut);
            }
        }
        // withdraw quote
        else {
            baseToken.safeTransfer(lp, baseAmount);
            amountOut = quoteAmount + IMagicLP(lp).sellBase(address(this));

            if (amountOut > 0) {
                quoteToken.safeTransfer(to, amountOut);
            }
        }

        if (amountOut < minAmountOut) {
            revert ErrTooHighSlippage(amountOut);
        }
    }

    function addLiquidityImbalanced(
        AddLiquidityImbalancedParams calldata params
    )
        public
        virtual
        ensureDeadline(params.deadline)
        onlyKnownPool(params.lp)
        returns (uint256 baseAdjustedInAmount, uint256 quoteAdjustedInAmount, uint256 shares)
    {
        address baseToken = IMagicLP(params.lp)._BASE_TOKEN_();
        address quoteToken = IMagicLP(params.lp)._QUOTE_TOKEN_();

        baseToken.safeTransferFrom(msg.sender, address(this), params.baseInAmount);
        quoteToken.safeTransferFrom(msg.sender, address(this), params.quoteInAmount);

        (baseAdjustedInAmount, quoteAdjustedInAmount) = _adjustAddLiquidity(params.lp, params.baseInAmount, params.quoteInAmount);

        // base -> quote
        if (params.remainingAmountToSwapIsBase) {
            baseToken.safeTransfer(params.lp, params.remainingAmountToSwap);
            baseAdjustedInAmount += (params.baseInAmount - baseAdjustedInAmount) - params.remainingAmountToSwap;
            quoteAdjustedInAmount += IMagicLP(params.lp).sellBase(address(this));
        }
        // quote -> base
        else {
            quoteToken.safeTransfer(params.lp, params.remainingAmountToSwap);
            baseAdjustedInAmount += IMagicLP(params.lp).sellQuote(address(this));
            quoteAdjustedInAmount += (params.quoteInAmount - quoteAdjustedInAmount) - params.remainingAmountToSwap;
        }

        (baseAdjustedInAmount, quoteAdjustedInAmount) = _adjustAddLiquidity(params.lp, baseAdjustedInAmount, quoteAdjustedInAmount);

        baseToken.safeTransfer(params.lp, baseAdjustedInAmount);
        quoteToken.safeTransfer(params.lp, quoteAdjustedInAmount);
        shares = _addLiquidity(params.lp, params.to, params.minimumShares);

        // Refund remaining tokens
        uint256 remaining = baseToken.balanceOf(address(this));
        if (remaining > 0) {
            baseToken.safeTransfer(msg.sender, remaining);
        }

        remaining = quoteToken.balanceOf(address(this));
        if (remaining > 0) {
            quoteToken.safeTransfer(msg.sender, remaining);
        }
    }

    //////////////////////////////////////////////////////////////////////////////////////
    /// INTERNALS
    //////////////////////////////////////////////////////////////////////////////////////

    function _addLiquidity(address lp, address to, uint256 minimumShares) internal returns (uint256 shares) {
        (shares, , ) = IMagicLP(lp).buyShares(to);

        if (shares < minimumShares) {
            revert ErrTooHighSlippage(shares);
        }
    }

    /// Adapted from: https://github.com/DODOEX/contractV2/blob/main/contracts/SmartRoute/proxies/DODODspProxy.sol
    /// Copyright 2020 DODO ZOO. Licensed under Apache-2.0.
    function _adjustAddLiquidity(
        address lp,
        uint256 baseInAmount,
        uint256 quoteInAmount
    ) internal view returns (uint256 baseAdjustedInAmount, uint256 quoteAdjustedInAmount) {
        if (IERC20(lp).totalSupply() == 0) {
            uint256 i = IMagicLP(lp)._I_();
            uint256 shares = quoteInAmount < DecimalMath.mulFloor(baseInAmount, i) ? DecimalMath.divFloor(quoteInAmount, i) : baseInAmount;
            baseAdjustedInAmount = shares;
            quoteAdjustedInAmount = DecimalMath.mulFloor(shares, i);
        } else {
            (uint256 baseReserve, uint256 quoteReserve) = IMagicLP(lp).getReserves();
            if (quoteReserve > 0 && baseReserve > 0) {
                uint256 baseIncreaseRatio = DecimalMath.divFloor(baseInAmount, baseReserve);
                uint256 quoteIncreaseRatio = DecimalMath.divFloor(quoteInAmount, quoteReserve);
                if (baseIncreaseRatio <= quoteIncreaseRatio) {
                    baseAdjustedInAmount = baseInAmount;
                    quoteAdjustedInAmount = DecimalMath.mulFloor(quoteReserve, baseIncreaseRatio);
                } else {
                    quoteAdjustedInAmount = quoteInAmount;
                    baseAdjustedInAmount = DecimalMath.mulFloor(baseReserve, quoteIncreaseRatio);
                }
            }
        }
    }

    function _swap(address to, address[] calldata path, uint256 directions, uint256 minimumOut) internal returns (uint256 amountOut) {
        uint256 iterations = path.length - 1; // Subtract by one as last swap is done separately

        for (uint256 i = 0; i < iterations; ) {
            address lp = path[i];
            if (!factory.poolExists(lp)) {
                revert ErrUnknownPool();
            }

            if (directions & 1 == 0) {
                // Sell base
                IMagicLP(lp).sellBase(address(path[i + 1]));
            } else {
                // Sell quote
                IMagicLP(lp).sellQuote(address(path[i + 1]));
            }

            directions >>= 1;

            unchecked {
                ++i;
            }
        }

        if ((directions & 1 == 0)) {
            amountOut = IMagicLP(path[iterations]).sellBase(to);
        } else {
            amountOut = IMagicLP(path[iterations]).sellQuote(to);
        }

        if (amountOut < minimumOut) {
            revert ErrTooHighSlippage(amountOut);
        }
    }

    function _sellBase(address lp, address to, uint256 minimumOut) internal returns (uint256 amountOut) {
        amountOut = IMagicLP(lp).sellBase(to);
        if (amountOut < minimumOut) {
            revert ErrTooHighSlippage(amountOut);
        }
    }

    function _sellQuote(address lp, address to, uint256 minimumOut) internal returns (uint256 amountOut) {
        amountOut = IMagicLP(lp).sellQuote(to);

        if (amountOut < minimumOut) {
            revert ErrTooHighSlippage(amountOut);
        }
    }

    function _validatePath(address[] calldata path) internal pure {
        uint256 pathLength = path.length;

        // Max 256 because of bits in directions
        if (pathLength > 256) {
            revert ErrPathTooLong();
        }
        if (pathLength <= 0) {
            revert ErrEmptyPath();
        }
    }

    function _validateDecimals(uint8 baseDecimals, uint8 quoteDecimals) internal pure {
        if (baseDecimals == 0 || quoteDecimals == 0) {
            revert ErrZeroDecimals();
        }

        if (baseDecimals > 18 || quoteDecimals > 18) {
            revert ErrTooLargeDecimals();
        }

        uint256 deltaDecimals = baseDecimals > quoteDecimals ? baseDecimals - quoteDecimals : quoteDecimals - baseDecimals;

        if (deltaDecimals > MAX_BASE_QUOTE_DECIMALS_DIFFERENCE) {
            revert ErrDecimalsDifferenceTooLarge();
        }
    }
}

File 4 of 17 : IWETH.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

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

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

    function withdraw(uint256) external;
}

interface IWETHAlike is IWETH {}

File 5 of 17 : IFactory.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

interface IFactory {
    function predictDeterministicAddress(
        address creator,
        address baseToken_,
        address quoteToken_,
        uint256 lpFeeRate_,
        uint256 i_,
        uint256 k_
    ) external view returns (address);

    function maintainerFeeRateModel() external view returns (address);

    function create(
        address baseToken_,
        address quoteToken_,
        uint256 lpFeeRate_,
        uint256 i_,
        uint256 k_,
        bool protocolOwnedPool_
    ) external returns (address clone);

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

    function addPool(address creator, address baseToken, address quoteToken, address pool) external;
}

File 6 of 17 : IBlast.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

enum YieldMode {
    AUTOMATIC,
    DISABLED,
    CLAIMABLE
}

enum GasMode {
    VOID,
    CLAIMABLE
}

interface IBlast {
    function governorMap(address) external view returns (address);

    // configure
    function configureContract(address contractAddress, YieldMode _yield, GasMode gasMode, address governor) external;

    function configure(YieldMode _yield, GasMode gasMode, address governor) external;

    // base configuration options
    function configureClaimableYield() external;

    function configureClaimableYieldOnBehalf(address contractAddress) external;

    function configureAutomaticYield() external;

    function configureAutomaticYieldOnBehalf(address contractAddress) external;

    function configureVoidYield() external;

    function configureVoidYieldOnBehalf(address contractAddress) external;

    function configureClaimableGas() external;

    function configureClaimableGasOnBehalf(address contractAddress) external;

    function configureVoidGas() external;

    function configureVoidGasOnBehalf(address contractAddress) external;

    function configureGovernor(address _governor) external;

    function configureGovernorOnBehalf(address _newGovernor, address contractAddress) external;

    // claim yield
    function claimYield(address contractAddress, address recipientOfYield, uint256 amount) external returns (uint256);

    function claimAllYield(address contractAddress, address recipientOfYield) external returns (uint256);

    // claim gas
    function claimAllGas(address contractAddress, address recipientOfGas) external returns (uint256);

    function claimGasAtMinClaimRate(address contractAddress, address recipientOfGas, uint256 minClaimRateBips) external returns (uint256);

    function claimMaxGas(address contractAddress, address recipientOfGas) external returns (uint256);

    function claimGas(
        address contractAddress,
        address recipientOfGas,
        uint256 gasToClaim,
        uint256 gasSecondsToConsume
    ) external returns (uint256);

    // read functions
    function readClaimableYield(address contractAddress) external view returns (uint256);

    function readYieldConfiguration(address contractAddress) external view returns (uint8);

    function readGasParams(
        address contractAddress
    ) external view returns (uint256 etherSeconds, uint256 etherBalance, uint256 lastUpdated, GasMode);
}

interface IERC20Rebasing {
    function getConfiguration(address account) external view returns (YieldMode);

    // changes the yield mode of the caller and update the balance
    // to reflect the configuration
    function configure(YieldMode) external returns (uint256);

    // "claimable" yield mode accounts can call this this claim their yield
    // to another address
    function claim(address recipient, uint256 amount) external returns (uint256);

    // read the claimable amount for an account
    function getClaimableAmount(address account) external view returns (uint256);
}

interface IBlastPoints {
    function configurePointsOperator(address operator) external;
}

File 7 of 17 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)

pragma solidity ^0.8.1;

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

        return account.code.length > 0;
    }

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

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

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

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

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

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

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

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

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

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}

File 8 of 17 : SafeTransferLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
///
/// @dev Note:
/// - For ETH transfers, please use `forceSafeTransferETH` for DoS protection.
/// - For ERC20s, this implementation won't check that a token has code,
///   responsibility is delegated to the caller.
library SafeTransferLib {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The ETH transfer has failed.
    error ETHTransferFailed();

    /// @dev The ERC20 `transferFrom` has failed.
    error TransferFromFailed();

    /// @dev The ERC20 `transfer` has failed.
    error TransferFailed();

    /// @dev The ERC20 `approve` has failed.
    error ApproveFailed();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         CONSTANTS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Suggested gas stipend for contract receiving ETH that disallows any storage writes.
    uint256 internal constant GAS_STIPEND_NO_STORAGE_WRITES = 2300;

    /// @dev Suggested gas stipend for contract receiving ETH to perform a few
    /// storage reads and writes, but low enough to prevent griefing.
    uint256 internal constant GAS_STIPEND_NO_GRIEF = 100000;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       ETH OPERATIONS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // If the ETH transfer MUST succeed with a reasonable gas budget, use the force variants.
    //
    // The regular variants:
    // - Forwards all remaining gas to the target.
    // - Reverts if the target reverts.
    // - Reverts if the current contract has insufficient balance.
    //
    // The force variants:
    // - Forwards with an optional gas stipend
    //   (defaults to `GAS_STIPEND_NO_GRIEF`, which is sufficient for most cases).
    // - If the target reverts, or if the gas stipend is exhausted,
    //   creates a temporary contract to force send the ETH via `SELFDESTRUCT`.
    //   Future compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758.
    // - Reverts if the current contract has insufficient balance.
    //
    // The try variants:
    // - Forwards with a mandatory gas stipend.
    // - Instead of reverting, returns whether the transfer succeeded.

    /// @dev Sends `amount` (in wei) ETH to `to`.
    function safeTransferETH(address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(call(gas(), to, amount, codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Sends all the ETH in the current contract to `to`.
    function safeTransferAllETH(address to) internal {
        /// @solidity memory-safe-assembly
        assembly {
            // Transfer all the ETH and check if it succeeded or not.
            if iszero(call(gas(), to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Force sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
    function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if lt(selfbalance(), amount) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
            if iszero(call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Force sends all the ETH in the current contract to `to`, with a `gasStipend`.
    function forceSafeTransferAllETH(address to, uint256 gasStipend) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Force sends `amount` (in wei) ETH to `to`, with `GAS_STIPEND_NO_GRIEF`.
    function forceSafeTransferETH(address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if lt(selfbalance(), amount) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
            if iszero(call(GAS_STIPEND_NO_GRIEF, to, amount, codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Force sends all the ETH in the current contract to `to`, with `GAS_STIPEND_NO_GRIEF`.
    function forceSafeTransferAllETH(address to) internal {
        /// @solidity memory-safe-assembly
        assembly {
            // forgefmt: disable-next-item
            if iszero(call(GAS_STIPEND_NO_GRIEF, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
    function trySafeTransferETH(address to, uint256 amount, uint256 gasStipend)
        internal
        returns (bool success)
    {
        /// @solidity memory-safe-assembly
        assembly {
            success := call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)
        }
    }

    /// @dev Sends all the ETH in the current contract to `to`, with a `gasStipend`.
    function trySafeTransferAllETH(address to, uint256 gasStipend)
        internal
        returns (bool success)
    {
        /// @solidity memory-safe-assembly
        assembly {
            success := call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      ERC20 OPERATIONS                      */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
    /// Reverts upon failure.
    ///
    /// The `from` account must have at least `amount` approved for
    /// the current contract to manage.
    function safeTransferFrom(address token, address from, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x60, amount) // Store the `amount` argument.
            mstore(0x40, to) // Store the `to` argument.
            mstore(0x2c, shl(96, from)) // Store the `from` argument.
            mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`.
            // Perform the transfer, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Sends all of ERC20 `token` from `from` to `to`.
    /// Reverts upon failure.
    ///
    /// The `from` account must have their entire balance approved for
    /// the current contract to manage.
    function safeTransferAllFrom(address token, address from, address to)
        internal
        returns (uint256 amount)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x40, to) // Store the `to` argument.
            mstore(0x2c, shl(96, from)) // Store the `from` argument.
            mstore(0x0c, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
            // Read the balance, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                    staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20)
                )
            ) {
                mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x00, 0x23b872dd) // `transferFrom(address,address,uint256)`.
            amount := mload(0x60) // The `amount` is already at 0x60. We'll need to return it.
            // Perform the transfer, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Sends `amount` of ERC20 `token` from the current contract to `to`.
    /// Reverts upon failure.
    function safeTransfer(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
            // Perform the transfer, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Sends all of ERC20 `token` from the current contract to `to`.
    /// Reverts upon failure.
    function safeTransferAll(address token, address to) internal returns (uint256 amount) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`.
            mstore(0x20, address()) // Store the address of the current contract.
            // Read the balance, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                    staticcall(gas(), token, 0x1c, 0x24, 0x34, 0x20)
                )
            ) {
                mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x14, to) // Store the `to` argument.
            amount := mload(0x34) // The `amount` is already at 0x34. We'll need to return it.
            mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
            // Perform the transfer, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
    /// Reverts upon failure.
    function safeApprove(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
            // Perform the approval, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
    /// If the initial attempt to approve fails, attempts to reset the approved amount to zero,
    /// then retries the approval again (some tokens, e.g. USDT, requires this).
    /// Reverts upon failure.
    function safeApproveWithRetry(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
            // Perform the approval, retrying upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                mstore(0x34, 0) // Store 0 for the `amount`.
                mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
                pop(call(gas(), token, 0, 0x10, 0x44, codesize(), 0x00)) // Reset the approval.
                mstore(0x34, amount) // Store back the original `amount`.
                // Retry the approval, reverting upon failure.
                if iszero(
                    and(
                        or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                        call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                    )
                ) {
                    mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
                    revert(0x1c, 0x04)
                }
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Returns the amount of ERC20 `token` owned by `account`.
    /// Returns zero if the `token` does not exist.
    function balanceOf(address token, address account) internal view returns (uint256 amount) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, account) // Store the `account` argument.
            mstore(0x00, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
            amount :=
                mul(
                    mload(0x20),
                    and( // The arguments of `and` are evaluated from right to left.
                        gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                        staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20)
                    )
                )
        }
    }
}

File 9 of 17 : 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 10 of 17 : Math.sol
/*

    Copyright 2020 DODO ZOO.
    SPDX-License-Identifier: Apache-2.0

*/

pragma solidity >=0.8.0;

import {DecimalMath} from "/mimswap/libraries/DecimalMath.sol";

/**
 * @author Adapted from https://github.com/DODOEX/contractV2/blob/main/contracts/lib/Math.sol
 * @notice Functions for complex calculating. Including ONE Integration and TWO Quadratic solutions
 */
library Math {
    error ErrIsZero();

    function divCeil(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 quotient = a / b;
        uint256 remainder = a - quotient * b;
        if (remainder > 0) {
            return quotient + 1;
        } else {
            return quotient;
        }
    }

    // babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method)
    // from UniswapV2 https://github.com/Uniswap/v2-core/blob/master/contracts/libraries/Math.sol
    function sqrt(uint y) internal pure returns (uint z) {
        if (y > 3) {
            z = y;
            uint x = y / 2 + 1;
            while (x < z) {
                z = x;
                x = (y / x + x) / 2;
            }
        } else if (y != 0) {
            z = 1;
        }
    }

    /*
        Integrate dodo curve from V1 to V2
        require V0>=V1>=V2>0
        res = (1-k)i(V1-V2)+ikV0*V0(1/V2-1/V1)
        let V1-V2=delta
        res = i*delta*(1-k+k(V0^2/V1/V2))

        i is the price of V-res trading pair

        support k=1 & k=0 case

        [round down]
    */
    function _GeneralIntegrate(uint256 V0, uint256 V1, uint256 V2, uint256 i, uint256 k) internal pure returns (uint256) {
        if (V0 == 0) {
            revert ErrIsZero();
        }

        uint256 fairAmount = i * (V1 - V2); // i*delta

        if (k == 0) {
            return fairAmount / DecimalMath.ONE;
        }

        uint256 V0V0V1V2 = DecimalMath.divFloor((V0 * V0) / V1, V2);
        uint256 penalty = DecimalMath.mulFloor(k, V0V0V1V2); // k(V0^2/V1/V2)
        return (((DecimalMath.ONE - k) + penalty) * fairAmount) / DecimalMath.ONE2;
    }

    /*
        Follow the integration function above
        i*deltaB = (Q2-Q1)*(1-k+kQ0^2/Q1/Q2)
        Assume Q2=Q0, Given Q1 and deltaB, solve Q0

        i is the price of delta-V trading pair
        give out target of V

        support k=1 & k=0 case

        [round down]
    */
    function _SolveQuadraticFunctionForTarget(uint256 V1, uint256 delta, uint256 i, uint256 k) internal pure returns (uint256) {
        if (k == 0) {
            return V1 + DecimalMath.mulFloor(i, delta);
        }

        // V0 = V1*(1+(sqrt-1)/2k)
        // sqrt = √(1+4kidelta/V1)
        // premium = 1+(sqrt-1)/2k
        // uint256 sqrt = (4 * k).mul(i).mul(delta).div(V1).add(DecimalMath.ONE2).sqrt();

        if (V1 == 0) {
            return 0;
        }
        uint256 _sqrt;
        uint256 ki = (4 * k) * i;
        if (ki == 0) {
            _sqrt = DecimalMath.ONE;
        } else if ((ki * delta) / ki == delta) {
            _sqrt = sqrt(((ki * delta) / V1) + DecimalMath.ONE2);
        } else {
            _sqrt = sqrt(((ki / V1) * delta) + DecimalMath.ONE2);
        }
        uint256 premium = DecimalMath.divFloor(_sqrt - DecimalMath.ONE, k * 2) + DecimalMath.ONE;
        // V0 is greater than or equal to V1 according to the solution
        return DecimalMath.mulFloor(V1, premium);
    }

    /*
        Follow the integration expression above, we have:
        i*deltaB = (Q2-Q1)*(1-k+kQ0^2/Q1/Q2)
        Given Q1 and deltaB, solve Q2
        This is a quadratic function and the standard version is
        aQ2^2 + bQ2 + c = 0, where
        a=1-k
        -b=(1-k)Q1-kQ0^2/Q1+i*deltaB
        c=-kQ0^2 
        and Q2=(-b+sqrt(b^2+4(1-k)kQ0^2))/2(1-k)
        note: another root is negative, abondan

        if deltaBSig=true, then Q2>Q1, user sell Q and receive B
        if deltaBSig=false, then Q2<Q1, user sell B and receive Q
        return |Q1-Q2|

        as we only support sell amount as delta, the deltaB is always negative
        the input ideltaB is actually -ideltaB in the equation

        i is the price of delta-V trading pair

        support k=1 & k=0 case

        [round down]
    */
    function _SolveQuadraticFunctionForTrade(uint256 V0, uint256 V1, uint256 delta, uint256 i, uint256 k) internal pure returns (uint256) {
        if (V0 == 0) {
            revert ErrIsZero();
        }

        if (delta == 0) {
            return 0;
        }

        if (k == 0) {
            return DecimalMath.mulFloor(i, delta) > V1 ? V1 : DecimalMath.mulFloor(i, delta);
        }

        if (k == DecimalMath.ONE) {
            // if k==1
            // Q2=Q1/(1+ideltaBQ1/Q0/Q0)
            // temp = ideltaBQ1/Q0/Q0
            // Q2 = Q1/(1+temp)
            // Q1-Q2 = Q1*(1-1/(1+temp)) = Q1*(temp/(1+temp))
            // uint256 temp = i.mul(delta).mul(V1).div(V0.mul(V0));
            uint256 temp;
            uint256 idelta = i * delta;
            if (idelta == 0) {
                temp = 0;
            } else if ((idelta * V1) / idelta == V1) {
                temp = (idelta * V1) / (V0 * V0);
            } else {
                temp = (((delta * V1) / V0) * i) / V0;
            }
            return (V1 * temp) / (temp + DecimalMath.ONE);
        }

        // calculate -b value and sig
        // b = kQ0^2/Q1-i*deltaB-(1-k)Q1
        // part1 = (1-k)Q1 >=0
        // part2 = kQ0^2/Q1-i*deltaB >=0
        // bAbs = abs(part1-part2)
        // if part1>part2 => b is negative => bSig is false
        // if part2>part1 => b is positive => bSig is true
        uint256 part2 = (((k * V0) / V1) * V0) + (i * delta); // kQ0^2/Q1-i*deltaB
        uint256 bAbs = (DecimalMath.ONE - k) * V1; // (1-k)Q1

        bool bSig;
        if (bAbs >= part2) {
            bAbs = bAbs - part2;
            bSig = false;
        } else {
            bAbs = part2 - bAbs;
            bSig = true;
        }
        bAbs = bAbs / DecimalMath.ONE;

        // calculate sqrt
        uint256 squareRoot = DecimalMath.mulFloor((DecimalMath.ONE - k) * 4, DecimalMath.mulFloor(k, V0) * V0); // 4(1-k)kQ0^2
        squareRoot = sqrt((bAbs * bAbs) + squareRoot); // sqrt(b*b+4(1-k)kQ0*Q0)

        // final res
        uint256 denominator = (DecimalMath.ONE - k) * 2; // 2(1-k)
        uint256 numerator;
        if (bSig) {
            numerator = squareRoot - bAbs;
            if (numerator == 0) {
                revert ErrIsZero();
            }
        } else {
            numerator = bAbs + squareRoot;
        }

        uint256 V2 = DecimalMath.divCeil(numerator, denominator);
        if (V2 > V1) {
            return 0;
        } else {
            return V1 - V2;
        }
    }
}

File 11 of 17 : DecimalMath.sol
/*

    Copyright 2020 DODO ZOO.
    SPDX-License-Identifier: Apache-2.0

*/
pragma solidity >=0.8.0;

import {Math} from "/mimswap/libraries/Math.sol";

/**
 * @title DecimalMath
 * @author DODO Breeder
 *
 * @notice Functions for fixed point number with 18 decimals
 */
library DecimalMath {
    using Math for uint256;

    uint256 internal constant ONE = 10 ** 18;
    uint256 internal constant ONE2 = 10 ** 36;

    function mulFloor(uint256 target, uint256 d) internal pure returns (uint256) {
        return (target * d) / ONE;
    }

    function mulCeil(uint256 target, uint256 d) internal pure returns (uint256) {
        return (target * d).divCeil(ONE);
    }

    function divFloor(uint256 target, uint256 d) internal pure returns (uint256) {
        return (target * ONE) / d;
    }

    function divCeil(uint256 target, uint256 d) internal pure returns (uint256) {
        return (target * ONE).divCeil(d);
    }

    function reciprocalFloor(uint256 target) internal pure returns (uint256) {
        return ONE2 / target;
    }

    function reciprocalCeil(uint256 target) internal pure returns (uint256) {
        return ONE2.divCeil(target);
    }

    function powFloor(uint256 target, uint256 e) internal pure returns (uint256) {
        if (e == 0) {
            return 10 ** 18;
        } else if (e == 1) {
            return target;
        } else {
            uint p = powFloor(target, e / 2);
            p = (p * p) / ONE;
            if (e % 2 == 1) {
                p = (p * target) / ONE;
            }
            return p;
        }
    }
}

File 12 of 17 : IMagicLP.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.0;

interface IMagicLP {
    function _BASE_TOKEN_() external view returns (address);

    function _QUOTE_TOKEN_() external view returns (address);

    function _BASE_RESERVE_() external view returns (uint112);

    function _QUOTE_RESERVE_() external view returns (uint112);

    function _BASE_TARGET_() external view returns (uint112);

    function _QUOTE_TARGET_() external view returns (uint112);

    function _I_() external view returns (uint256);

    function getReserves() external view returns (uint256 baseReserve, uint256 quoteReserve);

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

    function init(
        address baseTokenAddress,
        address quoteTokenAddress,
        uint256 lpFeeRate,
        address mtFeeRateModel,
        uint256 i,
        uint256 k,
        bool protocolOwnedPool
    ) external;

    function sellBase(address to) external returns (uint256 receiveQuoteAmount);

    function sellQuote(address to) external returns (uint256 receiveBaseAmount);

    function flashLoan(uint256 baseAmount, uint256 quoteAmount, address assetTo, bytes calldata data) external;

    function buyShares(address to) external returns (uint256 shares, uint256 baseInput, uint256 quoteInput);

    function sellShares(
        uint256 shareAmount,
        address to,
        uint256 baseMinAmount,
        uint256 quoteMinAmount,
        bytes calldata data,
        uint256 deadline
    ) external returns (uint256 baseAmount, uint256 quoteAmount);

    function MIN_LP_FEE_RATE() external view returns (uint256);

    function MAX_LP_FEE_RATE() external view returns (uint256);

    function _PAUSED_() external view returns (bool);

    function setPaused(bool paused) external;
}

File 13 of 17 : IERC20Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC20Metadata.sol)

pragma solidity ^0.8.0;

import "../token/ERC20/extensions/IERC20Metadata.sol";

File 14 of 17 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Reentrancy guard mixin.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ReentrancyGuard.sol)
abstract contract ReentrancyGuard {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Unauthorized reentrant call.
    error Reentrancy();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                          STORAGE                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Equivalent to: `uint72(bytes9(keccak256("_REENTRANCY_GUARD_SLOT")))`.
    /// 9 bytes is large enough to avoid collisions with lower slots,
    /// but not too large to result in excessive bytecode bloat.
    uint256 private constant _REENTRANCY_GUARD_SLOT = 0x929eee149b4bd21268;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      REENTRANCY GUARD                      */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Guards a function from reentrancy.
    modifier nonReentrant() virtual {
        /// @solidity memory-safe-assembly
        assembly {
            if eq(sload(_REENTRANCY_GUARD_SLOT), address()) {
                mstore(0x00, 0xab143c06) // `Reentrancy()`.
                revert(0x1c, 0x04)
            }
            sstore(_REENTRANCY_GUARD_SLOT, address())
        }
        _;
        /// @solidity memory-safe-assembly
        assembly {
            sstore(_REENTRANCY_GUARD_SLOT, codesize())
        }
    }

    /// @dev Guards a view function from read-only reentrancy.
    modifier nonReadReentrant() virtual {
        /// @solidity memory-safe-assembly
        assembly {
            if eq(sload(_REENTRANCY_GUARD_SLOT), address()) {
                mstore(0x00, 0xab143c06) // `Reentrancy()`.
                revert(0x1c, 0x04)
            }
        }
        _;
    }
}

File 15 of 17 : IERC20.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IERC20 {
    // transfer and tranferFrom have been removed, because they don't work on all tokens (some aren't ERC20 complaint).
    // By removing them you can't accidentally use them.
    // name, symbol and decimals have been removed, because they are optional and sometimes wrongly implemented (MKR).
    // Use BoringERC20 with `using BoringERC20 for IERC20` and call `safeTransfer`, `safeTransferFrom`, etc instead.
    function totalSupply() external view returns (uint256);

    function balanceOf(address account) external view returns (uint256);

    function allowance(address owner, address spender) external view returns (uint256);

    function approve(address spender, uint256 amount) external returns (bool);

    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /// @notice EIP 2612
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;
}

interface IStrictERC20 {
    // This is the strict ERC20 interface. Don't use this, certainly not if you don't control the ERC20 token you're calling.
    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function decimals() external view returns (uint8);
    function totalSupply() external view returns (uint256);
    function balanceOf(address _owner) external view returns (uint256 balance);
    function transfer(address _to, uint256 _value) external returns (bool success);
    function transferFrom(address _from, address _to, uint256 _value) external returns (bool success);
    function approve(address _spender, uint256 _value) external returns (bool success);
    function allowance(address _owner, address _spender) external view returns (uint256 remaining);

    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /// @notice EIP 2612
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;
}

File 16 of 17 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.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 17 of 17 : IERC20Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";

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

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

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

Settings
{
  "remappings": [
    "/=src/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/",
    "BoringSolidity/=lib/BoringSolidity/contracts/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/",
    "solmate/=lib/solmate/src/",
    "utils/=utils/",
    "libraries/=src/libraries/",
    "interfaces/=src/interfaces/",
    "cauldrons/=src/cauldrons/",
    "staking/=src/staking/",
    "swappers/=src/swappers/",
    "oracles/=src/oracles/",
    "strategies/=src/strategies/",
    "tokens/=src/tokens/",
    "periphery/=src/periphery/",
    "mixins/=src/mixins/",
    "lenses/=src/lenses/",
    "surl/=lib/surl/src/",
    "solady/=lib/solady/src/",
    "forge-deploy/=lib/forge-deploy/contracts/",
    "ExcessivelySafeCall/=lib/ExcessivelySafeCall/src/",
    "safe-contracts/=lib/safe-contracts/contracts/",
    "fuzzlib/=lib/fuzzlib/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 400
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "viaIR": false,
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"contract IWETH","name":"weth_","type":"address"},{"internalType":"contract IFactory","name":"factory","type":"address"},{"internalType":"address","name":"governor_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ErrBadPath","type":"error"},{"inputs":[],"name":"ErrDecimalsDifferenceTooLarge","type":"error"},{"inputs":[],"name":"ErrEmptyPath","type":"error"},{"inputs":[],"name":"ErrExpired","type":"error"},{"inputs":[],"name":"ErrInTokenNotETH","type":"error"},{"inputs":[],"name":"ErrInvalidBaseToken","type":"error"},{"inputs":[],"name":"ErrInvalidQuoteTarget","type":"error"},{"inputs":[],"name":"ErrInvalidQuoteToken","type":"error"},{"inputs":[],"name":"ErrNotETHLP","type":"error"},{"inputs":[],"name":"ErrOutTokenNotETH","type":"error"},{"inputs":[],"name":"ErrPathTooLong","type":"error"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"name":"ErrTooHighSlippage","type":"error"},{"inputs":[],"name":"ErrTooLargeDecimals","type":"error"},{"inputs":[],"name":"ErrUnknownPool","type":"error"},{"inputs":[],"name":"ErrZeroAddress","type":"error"},{"inputs":[],"name":"ErrZeroDecimals","type":"error"},{"inputs":[],"name":"Reentrancy","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"contractAddress","type":"address"}],"name":"LogBlastNativeClaimableEnabled","type":"event"},{"inputs":[],"name":"MAX_BASE_QUOTE_DECIMALS_DIFFERENCE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"lp","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"baseInAmount","type":"uint256"},{"internalType":"uint256","name":"quoteInAmount","type":"uint256"},{"internalType":"uint256","name":"minimumShares","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidity","outputs":[{"internalType":"uint256","name":"baseAdjustedInAmount","type":"uint256"},{"internalType":"uint256","name":"quoteAdjustedInAmount","type":"uint256"},{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"lp","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address payable","name":"refundTo","type":"address"},{"internalType":"uint256","name":"tokenInAmount","type":"uint256"},{"internalType":"uint256","name":"minimumShares","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidityETH","outputs":[{"internalType":"uint256","name":"baseAdjustedInAmount","type":"uint256"},{"internalType":"uint256","name":"quoteAdjustedInAmount","type":"uint256"},{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"lp","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenInAmount","type":"uint256"},{"internalType":"uint256","name":"minimumShares","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidityETHUnsafe","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"lp","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"baseInAmount","type":"uint256"},{"internalType":"uint256","name":"quoteInAmount","type":"uint256"},{"internalType":"bool","name":"remainingAmountToSwapIsBase","type":"bool"},{"internalType":"uint256","name":"remainingAmountToSwap","type":"uint256"},{"internalType":"uint256","name":"minimumShares","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct AddLiquidityImbalancedParams","name":"params","type":"tuple"}],"name":"addLiquidityImbalanced","outputs":[{"internalType":"uint256","name":"baseAdjustedInAmount","type":"uint256"},{"internalType":"uint256","name":"quoteAdjustedInAmount","type":"uint256"},{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"lp","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"inAmountIsBase","type":"bool"},{"internalType":"uint256","name":"inAmount","type":"uint256"},{"internalType":"uint256","name":"inAmountToSwap","type":"uint256"},{"internalType":"uint256","name":"minimumShares","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidityOneSide","outputs":[{"internalType":"uint256","name":"baseAmount","type":"uint256"},{"internalType":"uint256","name":"quoteAmount","type":"uint256"},{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"lp","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"baseInAmount","type":"uint256"},{"internalType":"uint256","name":"quoteInAmount","type":"uint256"},{"internalType":"uint256","name":"minimumShares","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidityUnsafe","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"baseToken","type":"address"},{"internalType":"address","name":"quoteToken","type":"address"},{"internalType":"uint256","name":"lpFeeRate","type":"uint256"},{"internalType":"uint256","name":"i","type":"uint256"},{"internalType":"uint256","name":"k","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"baseInAmount","type":"uint256"},{"internalType":"uint256","name":"quoteInAmount","type":"uint256"},{"internalType":"bool","name":"protocolOwnedPool","type":"bool"}],"name":"createPool","outputs":[{"internalType":"address","name":"clone","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"bool","name":"useTokenAsQuote","type":"bool"},{"internalType":"uint256","name":"lpFeeRate","type":"uint256"},{"internalType":"uint256","name":"i","type":"uint256"},{"internalType":"uint256","name":"k","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenInAmount","type":"uint256"},{"internalType":"bool","name":"protocolOwnedPool","type":"bool"}],"name":"createPoolETH","outputs":[{"internalType":"address","name":"clone","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"contract IFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"i","type":"uint256"},{"internalType":"uint256","name":"baseInAmount","type":"uint256"},{"internalType":"uint256","name":"quoteInAmount","type":"uint256"}],"name":"previewCreatePool","outputs":[{"internalType":"uint256","name":"baseAdjustedInAmount","type":"uint256"},{"internalType":"uint256","name":"quoteAdjustedInAmount","type":"uint256"},{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"lp","type":"address"},{"internalType":"uint256","name":"sharesIn","type":"uint256"}],"name":"previewRemoveLiquidity","outputs":[{"internalType":"uint256","name":"baseAmountOut","type":"uint256"},{"internalType":"uint256","name":"quoteAmountOut","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"lp","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"sharesIn","type":"uint256"},{"internalType":"uint256","name":"minimumBaseAmount","type":"uint256"},{"internalType":"uint256","name":"minimumQuoteAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidity","outputs":[{"internalType":"uint256","name":"baseAmountOut","type":"uint256"},{"internalType":"uint256","name":"quoteAmountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"lp","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"sharesIn","type":"uint256"},{"internalType":"uint256","name":"minimumETHAmount","type":"uint256"},{"internalType":"uint256","name":"minimumTokenAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidityETH","outputs":[{"internalType":"uint256","name":"ethAmountOut","type":"uint256"},{"internalType":"uint256","name":"tokenAmountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"lp","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"withdrawBase","type":"bool"},{"internalType":"uint256","name":"sharesIn","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidityOneSide","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"lp","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"minimumOut","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"sellBaseETHForTokens","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"lp","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"minimumOut","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"sellBaseTokensForETH","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"lp","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"minimumOut","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"sellBaseTokensForTokens","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"lp","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"minimumOut","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"sellQuoteETHForTokens","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"lp","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"minimumOut","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"sellQuoteTokensForETH","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"lp","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"minimumOut","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"sellQuoteTokensForTokens","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"uint256","name":"directions","type":"uint256"},{"internalType":"uint256","name":"minimumOut","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapETHForTokens","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"uint256","name":"directions","type":"uint256"},{"internalType":"uint256","name":"minimumOut","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapTokensForETH","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"uint256","name":"directions","type":"uint256"},{"internalType":"uint256","name":"minimumOut","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapTokensForTokens","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"contract IWETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

60c06040523480156200001157600080fd5b5060405162004df538038062004df5833981016040819052620000349162000174565b82826001600160a01b03821615806200005457506001600160a01b038116155b156200007357604051630ecc6fdf60e41b815260040160405180910390fd5b6001600160a01b03918216608052811660a0528116620000a657604051630ecc6fdf60e41b815260040160405180910390fd5b620000b181620000ba565b5050506200022a565b60405163c8992e6160e01b81527343000000000000000000000000000000000000029063c8992e6190620000f9906002906001908690600401620001de565b600060405180830381600087803b1580156200011457600080fd5b505af115801562000129573d6000803e3d6000fd5b50506040513092507fd519de07dfc6a474caab5e77d5829a6ca71ad6a4aafc5cc253bafe0f0c772bf59150600090a250565b6001600160a01b03811681146200017157600080fd5b50565b6000806000606084860312156200018a57600080fd5b835162000197816200015b565b6020850151909350620001aa816200015b565b6040850151909250620001bd816200015b565b809150509250925092565b634e487b7160e01b600052602160045260246000fd5b6060810160038510620001f557620001f5620001c8565b848252600284106200020b576200020b620001c8565b60208201939093526001600160a01b0391909116604090910152919050565b60805160a051614a6a6200038b600039600081816104470152818161056601528181610ac701528181610d60015281816110a7015281816112070152818161138c015281816115b401528181611718015281816118a101528181611a7001528181611c9d0152818161207501528181612606015281816129a601528181612e1001528181612f2e0152818161317801528181613637015261403e0152600081816102e001528181610b0101528181610b2801528181610be001528181610c7601528181610dec01528181610f3a0152818161147e015281816114d00152818161192d0152818161216701528181612209015281816122bc0152818161233a015281816124c90152818161251b01528181612c0901528181612d4301528181613020015281816130720152818161326d01528181613325015281816133f30152818161346c0152818161373e0152818161387901526139bf0152614a6a6000f3fe60806040526004361061019a5760003560e01c80636525e5f1116100e1578063c45a01551161008a578063e3f88c0b11610064578063e3f88c0b146104a9578063f2ef5d5e146104bc578063f54d44cf146104cf578063f57829a0146104ef57600080fd5b8063c45a015514610435578063cb83172f14610469578063de3d7b7f1461048957600080fd5b80638454c89b116100bb5780638454c89b146103e2578063906205f1146103f55780639e9d406e1461041557600080fd5b80636525e5f11461038f578063807bd736146103af5780638095deca146103cf57600080fd5b806338a1134611610143578063442f60ec1161011d578063442f60ec1461031a57806344483d531461033a578063579a3ac21461036f57600080fd5b806338a113461461029b5780633f46376e146102ae5780633fc8cef3146102ce57600080fd5b80632f6419f9116101745780632f6419f9146102465780633351733f14610266578063337164b31461028657600080fd5b8063011266c3146101a65780630e8cdaba146101e65780631a8e9be91461021857600080fd5b366101a157005b600080fd5b3480156101b257600080fd5b506101c66101c13660046143aa565b61050f565b604080519384526020840192909252908201526060015b60405180910390f35b6101f96101f43660046143e9565b6109df565b604080516001600160a01b0390931683526020830191909152016101dd565b34801561022457600080fd5b5061023861023336600461446e565b610d1b565b6040519081526020016101dd565b34801561025257600080fd5b506101f96102613660046144bf565b610fbd565b34801561027257600080fd5b506101c661028136600461454e565b6111bf565b34801561029257600080fd5b50610238600c81565b6102386102a93660046145a7565b611347565b3480156102ba57600080fd5b506102386102c936600461446e565b61156f565b3480156102da57600080fd5b506103027f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016101dd565b34801561032657600080fd5b506101c66103353660046145ed565b61168d565b34801561034657600080fd5b5061035a61035536600461454e565b6116f2565b604080519283526020830191909152016101dd565b34801561037b57600080fd5b5061023861038a36600461446e565b61185c565b34801561039b57600080fd5b5061035a6103aa366004614619565b611a2d565b3480156103bb57600080fd5b506102386103ca366004614645565b611c58565b6102386103dd36600461446e565b612030565b6102386103f03660046146f6565b612392565b34801561040157600080fd5b506101c6610410366004614765565b6125be565b34801561042157600080fd5b5061023861043036600461454e565b612961565b34801561044157600080fd5b506103027f000000000000000000000000000000000000000000000000000000000000000081565b34801561047557600080fd5b506102386104843660046147d3565b612ac3565b34801561049557600080fd5b506102386104a436600461446e565b612dcb565b6102386104b73660046145a7565b612ee9565b6101c66104ca36600461484a565b613105565b3480156104db57600080fd5b506102386104ea3660046147d3565b613512565b3480156104fb57600080fd5b5061035a61050a36600461454e565b613611565b60008060008360e001358042111561053a57604051630992d5df60e41b815260040160405180910390fd5b610547602086018661488e565b604051631e1c6a0760e01b81526001600160a01b0382811660048301527f00000000000000000000000000000000000000000000000000000000000000001690631e1c6a0790602401602060405180830381865afa1580156105ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105d191906148ab565b6105ee576040516392c46cf760e01b815260040160405180910390fd5b60006105fd602088018861488e565b6001600160a01b0316634a248d2a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561063a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061065e91906148c8565b9050600061066f602089018961488e565b6001600160a01b031663d4b970466040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106d091906148c8565b90506106eb6001600160a01b038316333060408c0135613a58565b6107046001600160a01b038216333060608c0135613a58565b61072361071460208a018a61488e565b89604001358a60600135613ab5565b909750955061073860a0890160808a016148e5565b156108155761076261074d60208a018a61488e565b6001600160a01b0384169060a08b0135613c93565b60a08801356107758860408b0135614918565b61077f9190614918565b610789908861492b565b9650610798602089018961488e565b604051632f58056d60e21b81523060048201526001600160a01b03919091169063bd6015b4906024016020604051808303816000875af11580156107e0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610804919061493e565b61080e908761492b565b95506108e9565b61083a61082560208a018a61488e565b6001600160a01b0383169060a08b0135613c93565b610847602089018961488e565b604051636ec9facd60e11b81523060048201526001600160a01b03919091169063dd93f59a906024016020604051808303816000875af115801561088f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108b3919061493e565b6108bd908861492b565b965060a08801356108d28760608b0135614918565b6108dc9190614918565b6108e6908761492b565b95505b6109006108f960208a018a61488e565b8888613ab5565b909750955061092661091560208a018a61488e565b6001600160a01b0384169089613c93565b61094761093660208a018a61488e565b6001600160a01b0383169088613c93565b61097161095760208a018a61488e565b61096760408b0160208c0161488e565b8a60c00135613ce2565b945060006109886001600160a01b03841630613d82565b905080156109a4576109a46001600160a01b0384163383613c93565b6109b76001600160a01b03831630613d82565b905080156109d3576109d36001600160a01b0383163383613c93565b50505050509193909250565b6000808815610a5957610a5460128b6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a4f9190614957565b613db7565b610ac5565b610ac58a6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610abe9190614957565b6012613db7565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316636a132ea68a610aff578b610b21565b7f00000000000000000000000000000000000000000000000000000000000000005b8b610b4c577f0000000000000000000000000000000000000000000000000000000000000000610b4e565b8c5b6040516001600160e01b031960e085901b1681526001600160a01b03928316600482015291166024820152604481018b9052606481018a90526084810189905285151560a482015260c4016020604051808303816000875af1158015610bb8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bdc91906148c8565b91507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610c3957600080fd5b505af1158015610c4d573d6000803e3d6000fd5b50610c69935050506001600160a01b038c169050338487613a58565b610c9d6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168334613c93565b604051634c85b42560e01b81526001600160a01b038681166004830152831690634c85b425906024016060604051808303816000875af1158015610ce5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d09919061497a565b50929b909a5098505050505050505050565b60008180421115610d3f57604051630992d5df60e41b815260040160405180910390fd5b604051631e1c6a0760e01b81526001600160a01b03808916600483015288917f000000000000000000000000000000000000000000000000000000000000000090911690631e1c6a0790602401602060405180830381865afa158015610da9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dcd91906148ab565b610dea576040516392c46cf760e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316886001600160a01b0316634a248d2a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e52573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e7691906148c8565b6001600160a01b031614610e9d57604051632be739cb60e21b815260040160405180910390fd5b610f163389888b6001600160a01b031663d4b970466040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ee1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f0591906148c8565b6001600160a01b0316929190613a58565b610f21883087613e6d565b604051632e1a7d4d60e01b8152600481018290529093507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015610f8657600080fd5b505af1158015610f9a573d6000803e3d6000fd5b50610fb2925050506001600160a01b03881684613f04565b505095945050505050565b6000806110638b6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611001573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110259190614957565b8b6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a2b573d6000803e3d6000fd5b604051633509975360e11b81526001600160a01b038c811660048301528b81166024830152604482018b9052606482018a90526084820189905284151560a48301527f00000000000000000000000000000000000000000000000000000000000000001690636a132ea69060c4016020604051808303816000875af11580156110f0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061111491906148c8565b915061112b6001600160a01b038c16338488613a58565b6111406001600160a01b038b16338487613a58565b604051634c85b42560e01b81526001600160a01b038781166004830152831690634c85b425906024016060604051808303816000875af1158015611188573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111ac919061497a565b50929c909b509950505050505050505050565b600080600083804211156111e657604051630992d5df60e41b815260040160405180910390fd5b604051631e1c6a0760e01b81526001600160a01b03808c1660048301528b917f000000000000000000000000000000000000000000000000000000000000000090911690631e1c6a0790602401602060405180830381865afa158015611250573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061127491906148ab565b611291576040516392c46cf760e01b815260040160405180910390fd5b61129c8b8a8a613ab5565b80955081965050506112e8338c878e6001600160a01b0316634a248d2a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ee1573d6000803e3d6000fd5b61132c338c868e6001600160a01b031663d4b970466040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ee1573d6000803e3d6000fd5b6113378b8b89613ce2565b9250505096509650969350505050565b6000818042111561136b57604051630992d5df60e41b815260040160405180910390fd5b604051631e1c6a0760e01b81526001600160a01b03808816600483015287917f000000000000000000000000000000000000000000000000000000000000000090911690631e1c6a0790602401602060405180830381865afa1580156113d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113f991906148ab565b611416576040516392c46cf760e01b815260040160405180910390fd5b6000876001600160a01b0316634a248d2a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611456573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061147a91906148c8565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316146114ce57604051632be739cb60e21b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561152957600080fd5b505af115801561153d573d6000803e3d6000fd5b50611558935050506001600160a01b03831690508934613c93565b611563888888613f24565b98975050505050505050565b6000818042111561159357604051630992d5df60e41b815260040160405180910390fd5b604051631e1c6a0760e01b81526001600160a01b03808916600483015288917f000000000000000000000000000000000000000000000000000000000000000090911690631e1c6a0790602401602060405180830381865afa1580156115fd573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061162191906148ab565b61163e576040516392c46cf760e01b815260040160405180910390fd5b6116823389888b6001600160a01b031663d4b970466040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ee1573d6000803e3d6000fd5b611563888887613e6d565b600080600061169c8587613f56565b84106116a857846116b2565b6116b28487613f7e565b90508092506116c18187613f56565b91506107d181116116da575060009150819050806116e9565b6116e66103e982614918565b90505b93509350939050565b604051631e1c6a0760e01b81526001600160a01b038781166004830152600091829189917f000000000000000000000000000000000000000000000000000000000000000090911690631e1c6a0790602401602060405180830381865afa158015611761573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061178591906148ab565b6117a2576040516392c46cf760e01b815260040160405180910390fd5b6117b76001600160a01b038a1633308a613a58565b604051635ab6755360e11b8152600481018890526001600160a01b038981166024830152604482018890526064820187905260c06084830152600060c483015260a482018690528a169063b56ceaa69060e40160408051808303816000875af1158015611828573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061184c91906149a8565b9250925050965096945050505050565b6000818042111561188057604051630992d5df60e41b815260040160405180910390fd5b604051631e1c6a0760e01b81526001600160a01b03808916600483015288917f000000000000000000000000000000000000000000000000000000000000000090911690631e1c6a0790602401602060405180830381865afa1580156118ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061190e91906148ab565b61192b576040516392c46cf760e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316886001600160a01b031663d4b970466040518163ffffffff1660e01b8152600401602060405180830381865afa158015611993573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119b791906148c8565b6001600160a01b0316146119de5760405163807af6e560e01b815260040160405180910390fd5b611a223389888b6001600160a01b0316634a248d2a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ee1573d6000803e3d6000fd5b610f21883087613f24565b6000803068929eee149b4bd212685403611a4f5763ab143c066000526004601cfd5b604051631e1c6a0760e01b81526001600160a01b03808616600483015285917f000000000000000000000000000000000000000000000000000000000000000090911690631e1c6a0790602401602060405180830381865afa158015611ab9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611add91906148ab565b611afa576040516392c46cf760e01b815260040160405180910390fd5b6000611b7186876001600160a01b0316634a248d2a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b6291906148c8565b6001600160a01b031690613d82565b90506000611bb787886001600160a01b031663d4b970466040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b3e573d6000803e3d6000fd5b90506000876001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611bf9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c1d919061493e565b905080611c2a88856149cc565b611c3491906149e3565b955080611c4188846149cc565b611c4b91906149e3565b9450505050509250929050565b60008180421115611c7c57604051630992d5df60e41b815260040160405180910390fd5b604051631e1c6a0760e01b81526001600160a01b03808a16600483015289917f000000000000000000000000000000000000000000000000000000000000000090911690631e1c6a0790602401602060405180830381865afa158015611ce6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d0a91906148ab565b611d27576040516392c46cf760e01b815260040160405180910390fd5b6000896001600160a01b0316634a248d2a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d67573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d8b91906148c8565b905060008a6001600160a01b031663d4b970466040518163ffffffff1660e01b8152600401602060405180830381865afa158015611dcd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611df191906148c8565b9050611e086001600160a01b038c1633308b613a58565b604051635ab6755360e11b8152600481018990523060248201526000604482018190526064820181905260c0608483015260c4820181905260a482018890529081906001600160a01b038e169063b56ceaa69060e40160408051808303816000875af1158015611e7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ea091906149a8565b915091508a15611f5357611ebe6001600160a01b0384168e83613c93565b604051636ec9facd60e11b81523060048201526001600160a01b038e169063dd93f59a906024016020604051808303816000875af1158015611f04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f28919061493e565b611f32908361492b565b96508615611f4e57611f4e6001600160a01b0385168d89613c93565b611ff7565b611f676001600160a01b0385168e84613c93565b604051632f58056d60e21b81523060048201526001600160a01b038e169063bd6015b4906024016020604051808303816000875af1158015611fad573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fd1919061493e565b611fdb908261492b565b96508615611ff757611ff76001600160a01b0384168d89613c93565b8887101561202057604051632ff97dcd60e11b8152600481018890526024015b60405180910390fd5b5050505050509695505050505050565b6000818042111561205457604051630992d5df60e41b815260040160405180910390fd5b604051631e1c6a0760e01b81526001600160a01b03808916600483015288917f000000000000000000000000000000000000000000000000000000000000000090911690631e1c6a0790602401602060405180830381865afa1580156120be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120e291906148ab565b6120ff576040516392c46cf760e01b815260040160405180910390fd5b6000886001600160a01b0316634a248d2a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561213f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061216391906148c8565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b03160361220757886001600160a01b031663d4b970466040518163ffffffff1660e01b8152600401602060405180830381865afa1580156121dc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061220091906148c8565b90506122ba565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316896001600160a01b031663d4b970466040518163ffffffff1660e01b8152600401602060405180830381865afa15801561226f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061229391906148c8565b6001600160a01b0316146122ba57604051639700d1eb60e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561231557600080fd5b505af1158015612329573d6000803e3d6000fd5b506123659350506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691508b905034613c93565b61237a6001600160a01b038216338b8a613a58565b612385898988613ce2565b9998505050505050505050565b600081804211156123b657604051630992d5df60e41b815260040160405180910390fd5b6123c08787613f93565b6000878760008181106123d5576123d5614a05565b90506020020160208101906123ea919061488e565b905060008660011660000361246257816001600160a01b0316634a248d2a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612437573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061245b91906148c8565b90506124c7565b816001600160a01b031663d4b970466040518163ffffffff1660e01b8152600401602060405180830381865afa1580156124a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124c491906148c8565b90505b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316146125195760405163b1e72b7960e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561257457600080fd5b505af1158015612588573d6000803e3d6000fd5b506125a3935050506001600160a01b03831690508334613c93565b6125b08a8a8a8a8a613fd8565b9a9950505050505050505050565b600080600083804211156125e557604051630992d5df60e41b815260040160405180910390fd5b604051631e1c6a0760e01b81526001600160a01b03808d1660048301528c917f000000000000000000000000000000000000000000000000000000000000000090911690631e1c6a0790602401602060405180830381865afa15801561264f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061267391906148ab565b612690576040516392c46cf760e01b815260040160405180910390fd5b60008c6001600160a01b0316634a248d2a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156126d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126f491906148c8565b905060008d6001600160a01b031663d4b970466040518163ffffffff1660e01b8152600401602060405180830381865afa158015612736573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061275a91906148c8565b90508b15612808576127776001600160a01b03831633308e613a58565b6127818a8c614918565b96506127976001600160a01b0383168f8c613c93565b604051632f58056d60e21b81523060048201526001600160a01b038f169063bd6015b4906024016020604051808303816000875af11580156127dd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612801919061493e565b95506128aa565b61281d6001600160a01b03821633308e613a58565b6128278a8c614918565b955061283d6001600160a01b0382168f8c613c93565b604051636ec9facd60e11b81523060048201526001600160a01b038f169063dd93f59a906024016020604051808303816000875af1158015612883573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128a7919061493e565b96505b6128b58e8888613ab5565b90975095506128ce6001600160a01b0383168f89613c93565b6128e26001600160a01b0382168f88613c93565b6128ed8e8e8b613ce2565b945060006129046001600160a01b03841630613d82565b90508015612920576129206001600160a01b0384163383613c93565b6129336001600160a01b03831630613d82565b9050801561294f5761294f6001600160a01b0383163383613c93565b50505050509750975097945050505050565b6000818042111561298557604051630992d5df60e41b815260040160405180910390fd5b604051631e1c6a0760e01b81526001600160a01b03808a16600483015289917f000000000000000000000000000000000000000000000000000000000000000090911690631e1c6a0790602401602060405180830381865afa1580156129ef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a1391906148ab565b612a30576040516392c46cf760e01b815260040160405180910390fd5b612a74338a898c6001600160a01b0316634a248d2a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ee1573d6000803e3d6000fd5b612ab8338a888c6001600160a01b031663d4b970466040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ee1573d6000803e3d6000fd5b612385898987613ce2565b60008180421115612ae757604051630992d5df60e41b815260040160405180910390fd5b612af18787613f93565b6000612afe600188614918565b90506000888883818110612b1457612b14614a05565b9050602002016020810190612b29919061488e565b90506000600188841c168103612ba257816001600160a01b031663d4b970466040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b77573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b9b91906148c8565b9050612c07565b816001600160a01b0316634a248d2a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612be0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c0491906148c8565b90505b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b031614612c59576040516365ba5f2960e01b815260040160405180910390fd5b60008a8a6000818110612c6e57612c6e614a05565b9050602002016020810190612c83919061488e565b905088600116600003612cd957612cd433828e846001600160a01b0316634a248d2a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ee1573d6000803e3d6000fd5b612d1d565b612d1d33828e846001600160a01b031663d4b970466040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ee1573d6000803e3d6000fd5b612d2a308c8c8c8c613fd8565b604051632e1a7d4d60e01b8152600481018290529096507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015612d8f57600080fd5b505af1158015612da3573d6000803e3d6000fd5b50612dbb925050506001600160a01b038e1687613f04565b5050505050979650505050505050565b60008180421115612def57604051630992d5df60e41b815260040160405180910390fd5b604051631e1c6a0760e01b81526001600160a01b03808916600483015288917f000000000000000000000000000000000000000000000000000000000000000090911690631e1c6a0790602401602060405180830381865afa158015612e59573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e7d91906148ab565b612e9a576040516392c46cf760e01b815260040160405180910390fd5b612ede3389888b6001600160a01b0316634a248d2a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ee1573d6000803e3d6000fd5b611563888887613f24565b60008180421115612f0d57604051630992d5df60e41b815260040160405180910390fd5b604051631e1c6a0760e01b81526001600160a01b03808816600483015287917f000000000000000000000000000000000000000000000000000000000000000090911690631e1c6a0790602401602060405180830381865afa158015612f77573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f9b91906148ab565b612fb8576040516392c46cf760e01b815260040160405180910390fd5b6000876001600160a01b031663d4b970466040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ff8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061301c91906148c8565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316146130705760405163807af6e560e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b1580156130cb57600080fd5b505af11580156130df573d6000803e3d6000fd5b506130fa935050506001600160a01b03831690508934613c93565b611563888888613e6d565b60008060003068929eee149b4bd2126854036131295763ab143c066000526004601cfd5b3068929eee149b4bd2126855838042111561315757604051630992d5df60e41b815260040160405180910390fd5b604051631e1c6a0760e01b81526001600160a01b03808c1660048301528b917f000000000000000000000000000000000000000000000000000000000000000090911690631e1c6a0790602401602060405180830381865afa1580156131c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131e591906148ab565b613202576040516392c46cf760e01b815260040160405180910390fd5b60008060008d6001600160a01b0316634a248d2a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613245573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061326991906148c8565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b031603613323578d6001600160a01b031663d4b970466040518163ffffffff1660e01b8152600401602060405180830381865afa1580156132e2573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061330691906148c8565b90506133138e348d613ab5565b90985096508792508691506133f1565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168e6001600160a01b031663d4b970466040518163ffffffff1660e01b8152600401602060405180830381865afa15801561338b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133af91906148c8565b6001600160a01b0316036133d8576133c88e8c34613ab5565b90985096508692508791506133f1565b604051639700d1eb60e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0846040518263ffffffff1660e01b81526004016000604051808303818588803b15801561344c57600080fd5b505af1158015613460573d6000803e3d6000fd5b50505050506134a38e847f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316613c939092919063ffffffff16565b823411156134c8576134c86134b88434614918565b6001600160a01b038e1690613f04565b6134e8338f84846001600160a01b0316613a58909392919063ffffffff16565b6134f38e8e8c613ce2565b955050505050503868929eee149b4bd212685596509650969350505050565b6000818042111561353657604051630992d5df60e41b815260040160405180910390fd5b6135408787613f93565b60008787600081811061355557613555614a05565b905060200201602081019061356a919061488e565b9050856001166000036135c0576135bb33828b846001600160a01b0316634a248d2a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ee1573d6000803e3d6000fd5b613604565b61360433828b846001600160a01b031663d4b970466040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ee1573d6000803e3d6000fd5b6125b08a89898989613fd8565b604051631e1c6a0760e01b81526001600160a01b038781166004830152600091829189917f000000000000000000000000000000000000000000000000000000000000000090911690631e1c6a0790602401602060405180830381865afa158015613680573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136a491906148ab565b6136c1576040516392c46cf760e01b815260040160405180910390fd5b6136d66001600160a01b038a1633308a613a58565b6000896001600160a01b0316634a248d2a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613716573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061373a91906148c8565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b03160361387757896001600160a01b031663d4b970466040518163ffffffff1660e01b8152600401602060405180830381865afa1580156137b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137d791906148c8565b604051635ab6755360e11b8152600481018a9052306024820152604481018990526064810188905260c06084820152600060c482015260a481018790529091506001600160a01b038b169063b56ceaa69060e40160408051808303816000875af1158015613849573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061386d91906149a8565b90945092506139a9565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168a6001600160a01b031663d4b970466040518163ffffffff1660e01b8152600401602060405180830381865afa1580156138df573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061390391906148c8565b6001600160a01b0316036133d857604051635ab6755360e11b815260048101899052306024820152604481018790526064810188905260c06084820152600060c482015260a481018690526001600160a01b038b169063b56ceaa69060e40160408051808303816000875af1158015613980573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139a491906149a8565b945092505b604051632e1a7d4d60e01b8152600481018590527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015613a0b57600080fd5b505af1158015613a1f573d6000803e3d6000fd5b50613a37925050506001600160a01b038a1685613f04565b613a4b6001600160a01b0382168a85613c93565b5050965096945050505050565b60405181606052826040528360601b602c526f23b872dd000000000000000000000000600c52602060006064601c6000895af13d156001600051141716613aa757637939f4246000526004601cfd5b600060605260405250505050565b600080846001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613af6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b1a919061493e565b600003613bc1576000856001600160a01b031663f811d6926040518163ffffffff1660e01b8152600401602060405180830381865afa158015613b61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b85919061493e565b90506000613b938683613f56565b8510613b9f5785613ba9565b613ba98583613f7e565b9050809350613bb88183613f56565b92505050613c8b565b600080866001600160a01b0316630902f1ac6040518163ffffffff1660e01b81526004016040805180830381865afa158015613c01573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c2591906149a8565b91509150600081118015613c395750600082115b15613c88576000613c4a8784613f7e565b90506000613c588784613f7e565b9050808211613c7557879550613c6e8383613f56565b9450613c85565b869450613c828482613f56565b95505b50505b50505b935093915050565b81601452806034526fa9059cbb00000000000000000000000060005260206000604460106000875af13d156001600051141716613cd8576390b8ec186000526004601cfd5b6000603452505050565b604051634c85b42560e01b81526001600160a01b03838116600483015260009190851690634c85b425906024016060604051808303816000875af1158015613d2e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d52919061497a565b509091505081811015613d7b57604051632ff97dcd60e11b815260048101829052602401612017565b9392505050565b6000816014526f70a0823100000000000000000000000060005260208060246010865afa601f3d111660205102905092915050565b60ff82161580613dc8575060ff8116155b15613de65760405163ca1aefb560e01b815260040160405180910390fd5b60128260ff161180613dfb575060128160ff16115b15613e195760405163062d0f8560e51b815260040160405180910390fd5b60008160ff168360ff1611613e3757613e328383614a1b565b613e41565b613e418284614a1b565b60ff169050600c811115613e68576040516397088e6160e01b815260040160405180910390fd5b505050565b604051636ec9facd60e11b81526001600160a01b0383811660048301526000919085169063dd93f59a906024015b6020604051808303816000875af1158015613eba573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ede919061493e565b905081811015613d7b57604051632ff97dcd60e11b815260048101829052602401612017565b60003860003884865af1613f205763b12d13eb6000526004601cfd5b5050565b604051632f58056d60e21b81526001600160a01b0383811660048301526000919085169063bd6015b490602401613e9b565b6000670de0b6b3a7640000613f6b83856149cc565b613f7591906149e3565b90505b92915050565b600081613f6b670de0b6b3a7640000856149cc565b80610100811115613fb7576040516315e8dba360e01b815260040160405180910390fd5b60008111613e68576040516376ede79b60e11b815260040160405180910390fd5b600080613fe6600186614918565b905060005b8181101561423c57600087878381811061400757614007614a05565b905060200201602081019061401c919061488e565b604051631e1c6a0760e01b81526001600160a01b0380831660048301529192507f000000000000000000000000000000000000000000000000000000000000000090911690631e1c6a0790602401602060405180830381865afa158015614087573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140ab91906148ab565b6140c8576040516392c46cf760e01b815260040160405180910390fd5b85600116600003614183576001600160a01b03811663bd6015b489896140ef86600161492b565b8181106140fe576140fe614a05565b9050602002016020810190614113919061488e565b6040516001600160e01b031960e084901b1681526001600160a01b0390911660048201526024016020604051808303816000875af1158015614159573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061417d919061493e565b5061422f565b6001600160a01b03811663dd93f59a898961419f86600161492b565b8181106141ae576141ae614a05565b90506020020160208101906141c3919061488e565b6040516001600160e01b031960e084901b1681526001600160a01b0390911660048201526024016020604051808303816000875af1158015614209573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061422d919061493e565b505b50600194851c9401613feb565b50836001166000036142e45785858281811061425a5761425a614a05565b905060200201602081019061426f919061488e565b604051632f58056d60e21b81526001600160a01b038981166004830152919091169063bd6015b4906024016020604051808303816000875af11580156142b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142dd919061493e565b915061437c565b8585828181106142f6576142f6614a05565b905060200201602081019061430b919061488e565b604051636ec9facd60e11b81526001600160a01b038981166004830152919091169063dd93f59a906024016020604051808303816000875af1158015614355573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614379919061493e565b91505b828210156143a057604051632ff97dcd60e11b815260048101839052602401612017565b5095945050505050565b600061010082840312156143bd57600080fd5b50919050565b6001600160a01b03811681146143d857600080fd5b50565b80151581146143d857600080fd5b600080600080600080600080610100898b03121561440657600080fd5b8835614411816143c3565b97506020890135614421816143db565b965060408901359550606089013594506080890135935060a0890135614446816143c3565b925060c0890135915060e089013561445d816143db565b809150509295985092959890939650565b600080600080600060a0868803121561448657600080fd5b8535614491816143c3565b945060208601356144a1816143c3565b94979496505050506040830135926060810135926080909101359150565b60008060008060008060008060006101208a8c0312156144de57600080fd5b89356144e9816143c3565b985060208a01356144f9816143c3565b975060408a0135965060608a0135955060808a0135945060a08a013561451e816143c3565b935060c08a0135925060e08a013591506101008a013561453d816143db565b809150509295985092959850929598565b60008060008060008060c0878903121561456757600080fd5b8635614572816143c3565b95506020870135614582816143c3565b95989597505050506040840135936060810135936080820135935060a0909101359150565b600080600080608085870312156145bd57600080fd5b84356145c8816143c3565b935060208501356145d8816143c3565b93969395505050506040820135916060013590565b60008060006060848603121561460257600080fd5b505081359360208301359350604090920135919050565b6000806040838503121561462c57600080fd5b8235614637816143c3565b946020939093013593505050565b60008060008060008060c0878903121561465e57600080fd5b8635614669816143c3565b95506020870135614679816143c3565b94506040870135614689816143db565b959894975094956060810135955060808101359460a0909101359350915050565b60008083601f8401126146bc57600080fd5b50813567ffffffffffffffff8111156146d457600080fd5b6020830191508360208260051b85010111156146ef57600080fd5b9250929050565b60008060008060008060a0878903121561470f57600080fd5b863561471a816143c3565b9550602087013567ffffffffffffffff81111561473657600080fd5b61474289828a016146aa565b979a90995096976040810135976060820135975060809091013595509350505050565b600080600080600080600060e0888a03121561478057600080fd5b873561478b816143c3565b9650602088013561479b816143c3565b955060408801356147ab816143db565b969995985095966060810135965060808101359560a0820135955060c0909101359350915050565b600080600080600080600060c0888a0312156147ee57600080fd5b87356147f9816143c3565b965060208801359550604088013567ffffffffffffffff81111561481c57600080fd5b6148288a828b016146aa565b989b979a50986060810135976080820135975060a09091013595509350505050565b60008060008060008060c0878903121561486357600080fd5b863561486e816143c3565b9550602087013561487e816143c3565b94506040870135614689816143c3565b6000602082840312156148a057600080fd5b8135613d7b816143c3565b6000602082840312156148bd57600080fd5b8151613d7b816143db565b6000602082840312156148da57600080fd5b8151613d7b816143c3565b6000602082840312156148f757600080fd5b8135613d7b816143db565b634e487b7160e01b600052601160045260246000fd5b81810381811115613f7857613f78614902565b80820180821115613f7857613f78614902565b60006020828403121561495057600080fd5b5051919050565b60006020828403121561496957600080fd5b815160ff81168114613d7b57600080fd5b60008060006060848603121561498f57600080fd5b8351925060208401519150604084015190509250925092565b600080604083850312156149bb57600080fd5b505080516020909101519092909150565b8082028115828204841417613f7857613f78614902565b600082614a0057634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052603260045260246000fd5b60ff8281168282160390811115613f7857613f7861490256fea264697066735822122045228d232f7c69682bdc5876b4908b5797bead31ed44859911d15aa1e5911a6664736f6c6343000814003300000000000000000000000043000000000000000000000000000000000000040000000000000000000000007e05363e225c1c8096b1cd233b59457104b84908000000000000000000000000d69e75c1c2a0f2838a6bba8bdff9d08c8f137cd9

Deployed Bytecode

0x60806040526004361061019a5760003560e01c80636525e5f1116100e1578063c45a01551161008a578063e3f88c0b11610064578063e3f88c0b146104a9578063f2ef5d5e146104bc578063f54d44cf146104cf578063f57829a0146104ef57600080fd5b8063c45a015514610435578063cb83172f14610469578063de3d7b7f1461048957600080fd5b80638454c89b116100bb5780638454c89b146103e2578063906205f1146103f55780639e9d406e1461041557600080fd5b80636525e5f11461038f578063807bd736146103af5780638095deca146103cf57600080fd5b806338a1134611610143578063442f60ec1161011d578063442f60ec1461031a57806344483d531461033a578063579a3ac21461036f57600080fd5b806338a113461461029b5780633f46376e146102ae5780633fc8cef3146102ce57600080fd5b80632f6419f9116101745780632f6419f9146102465780633351733f14610266578063337164b31461028657600080fd5b8063011266c3146101a65780630e8cdaba146101e65780631a8e9be91461021857600080fd5b366101a157005b600080fd5b3480156101b257600080fd5b506101c66101c13660046143aa565b61050f565b604080519384526020840192909252908201526060015b60405180910390f35b6101f96101f43660046143e9565b6109df565b604080516001600160a01b0390931683526020830191909152016101dd565b34801561022457600080fd5b5061023861023336600461446e565b610d1b565b6040519081526020016101dd565b34801561025257600080fd5b506101f96102613660046144bf565b610fbd565b34801561027257600080fd5b506101c661028136600461454e565b6111bf565b34801561029257600080fd5b50610238600c81565b6102386102a93660046145a7565b611347565b3480156102ba57600080fd5b506102386102c936600461446e565b61156f565b3480156102da57600080fd5b506103027f000000000000000000000000430000000000000000000000000000000000000481565b6040516001600160a01b0390911681526020016101dd565b34801561032657600080fd5b506101c66103353660046145ed565b61168d565b34801561034657600080fd5b5061035a61035536600461454e565b6116f2565b604080519283526020830191909152016101dd565b34801561037b57600080fd5b5061023861038a36600461446e565b61185c565b34801561039b57600080fd5b5061035a6103aa366004614619565b611a2d565b3480156103bb57600080fd5b506102386103ca366004614645565b611c58565b6102386103dd36600461446e565b612030565b6102386103f03660046146f6565b612392565b34801561040157600080fd5b506101c6610410366004614765565b6125be565b34801561042157600080fd5b5061023861043036600461454e565b612961565b34801561044157600080fd5b506103027f0000000000000000000000007e05363e225c1c8096b1cd233b59457104b8490881565b34801561047557600080fd5b506102386104843660046147d3565b612ac3565b34801561049557600080fd5b506102386104a436600461446e565b612dcb565b6102386104b73660046145a7565b612ee9565b6101c66104ca36600461484a565b613105565b3480156104db57600080fd5b506102386104ea3660046147d3565b613512565b3480156104fb57600080fd5b5061035a61050a36600461454e565b613611565b60008060008360e001358042111561053a57604051630992d5df60e41b815260040160405180910390fd5b610547602086018661488e565b604051631e1c6a0760e01b81526001600160a01b0382811660048301527f0000000000000000000000007e05363e225c1c8096b1cd233b59457104b849081690631e1c6a0790602401602060405180830381865afa1580156105ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105d191906148ab565b6105ee576040516392c46cf760e01b815260040160405180910390fd5b60006105fd602088018861488e565b6001600160a01b0316634a248d2a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561063a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061065e91906148c8565b9050600061066f602089018961488e565b6001600160a01b031663d4b970466040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106d091906148c8565b90506106eb6001600160a01b038316333060408c0135613a58565b6107046001600160a01b038216333060608c0135613a58565b61072361071460208a018a61488e565b89604001358a60600135613ab5565b909750955061073860a0890160808a016148e5565b156108155761076261074d60208a018a61488e565b6001600160a01b0384169060a08b0135613c93565b60a08801356107758860408b0135614918565b61077f9190614918565b610789908861492b565b9650610798602089018961488e565b604051632f58056d60e21b81523060048201526001600160a01b03919091169063bd6015b4906024016020604051808303816000875af11580156107e0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610804919061493e565b61080e908761492b565b95506108e9565b61083a61082560208a018a61488e565b6001600160a01b0383169060a08b0135613c93565b610847602089018961488e565b604051636ec9facd60e11b81523060048201526001600160a01b03919091169063dd93f59a906024016020604051808303816000875af115801561088f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108b3919061493e565b6108bd908861492b565b965060a08801356108d28760608b0135614918565b6108dc9190614918565b6108e6908761492b565b95505b6109006108f960208a018a61488e565b8888613ab5565b909750955061092661091560208a018a61488e565b6001600160a01b0384169089613c93565b61094761093660208a018a61488e565b6001600160a01b0383169088613c93565b61097161095760208a018a61488e565b61096760408b0160208c0161488e565b8a60c00135613ce2565b945060006109886001600160a01b03841630613d82565b905080156109a4576109a46001600160a01b0384163383613c93565b6109b76001600160a01b03831630613d82565b905080156109d3576109d36001600160a01b0383163383613c93565b50505050509193909250565b6000808815610a5957610a5460128b6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a4f9190614957565b613db7565b610ac5565b610ac58a6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610abe9190614957565b6012613db7565b7f0000000000000000000000007e05363e225c1c8096b1cd233b59457104b849086001600160a01b0316636a132ea68a610aff578b610b21565b7f00000000000000000000000043000000000000000000000000000000000000045b8b610b4c577f0000000000000000000000004300000000000000000000000000000000000004610b4e565b8c5b6040516001600160e01b031960e085901b1681526001600160a01b03928316600482015291166024820152604481018b9052606481018a90526084810189905285151560a482015260c4016020604051808303816000875af1158015610bb8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bdc91906148c8565b91507f00000000000000000000000043000000000000000000000000000000000000046001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610c3957600080fd5b505af1158015610c4d573d6000803e3d6000fd5b50610c69935050506001600160a01b038c169050338487613a58565b610c9d6001600160a01b037f0000000000000000000000004300000000000000000000000000000000000004168334613c93565b604051634c85b42560e01b81526001600160a01b038681166004830152831690634c85b425906024016060604051808303816000875af1158015610ce5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d09919061497a565b50929b909a5098505050505050505050565b60008180421115610d3f57604051630992d5df60e41b815260040160405180910390fd5b604051631e1c6a0760e01b81526001600160a01b03808916600483015288917f0000000000000000000000007e05363e225c1c8096b1cd233b59457104b8490890911690631e1c6a0790602401602060405180830381865afa158015610da9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dcd91906148ab565b610dea576040516392c46cf760e01b815260040160405180910390fd5b7f00000000000000000000000043000000000000000000000000000000000000046001600160a01b0316886001600160a01b0316634a248d2a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e52573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e7691906148c8565b6001600160a01b031614610e9d57604051632be739cb60e21b815260040160405180910390fd5b610f163389888b6001600160a01b031663d4b970466040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ee1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f0591906148c8565b6001600160a01b0316929190613a58565b610f21883087613e6d565b604051632e1a7d4d60e01b8152600481018290529093507f00000000000000000000000043000000000000000000000000000000000000046001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015610f8657600080fd5b505af1158015610f9a573d6000803e3d6000fd5b50610fb2925050506001600160a01b03881684613f04565b505095945050505050565b6000806110638b6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611001573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110259190614957565b8b6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a2b573d6000803e3d6000fd5b604051633509975360e11b81526001600160a01b038c811660048301528b81166024830152604482018b9052606482018a90526084820189905284151560a48301527f0000000000000000000000007e05363e225c1c8096b1cd233b59457104b849081690636a132ea69060c4016020604051808303816000875af11580156110f0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061111491906148c8565b915061112b6001600160a01b038c16338488613a58565b6111406001600160a01b038b16338487613a58565b604051634c85b42560e01b81526001600160a01b038781166004830152831690634c85b425906024016060604051808303816000875af1158015611188573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111ac919061497a565b50929c909b509950505050505050505050565b600080600083804211156111e657604051630992d5df60e41b815260040160405180910390fd5b604051631e1c6a0760e01b81526001600160a01b03808c1660048301528b917f0000000000000000000000007e05363e225c1c8096b1cd233b59457104b8490890911690631e1c6a0790602401602060405180830381865afa158015611250573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061127491906148ab565b611291576040516392c46cf760e01b815260040160405180910390fd5b61129c8b8a8a613ab5565b80955081965050506112e8338c878e6001600160a01b0316634a248d2a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ee1573d6000803e3d6000fd5b61132c338c868e6001600160a01b031663d4b970466040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ee1573d6000803e3d6000fd5b6113378b8b89613ce2565b9250505096509650969350505050565b6000818042111561136b57604051630992d5df60e41b815260040160405180910390fd5b604051631e1c6a0760e01b81526001600160a01b03808816600483015287917f0000000000000000000000007e05363e225c1c8096b1cd233b59457104b8490890911690631e1c6a0790602401602060405180830381865afa1580156113d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113f991906148ab565b611416576040516392c46cf760e01b815260040160405180910390fd5b6000876001600160a01b0316634a248d2a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611456573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061147a91906148c8565b90507f00000000000000000000000043000000000000000000000000000000000000046001600160a01b0316816001600160a01b0316146114ce57604051632be739cb60e21b815260040160405180910390fd5b7f00000000000000000000000043000000000000000000000000000000000000046001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561152957600080fd5b505af115801561153d573d6000803e3d6000fd5b50611558935050506001600160a01b03831690508934613c93565b611563888888613f24565b98975050505050505050565b6000818042111561159357604051630992d5df60e41b815260040160405180910390fd5b604051631e1c6a0760e01b81526001600160a01b03808916600483015288917f0000000000000000000000007e05363e225c1c8096b1cd233b59457104b8490890911690631e1c6a0790602401602060405180830381865afa1580156115fd573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061162191906148ab565b61163e576040516392c46cf760e01b815260040160405180910390fd5b6116823389888b6001600160a01b031663d4b970466040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ee1573d6000803e3d6000fd5b611563888887613e6d565b600080600061169c8587613f56565b84106116a857846116b2565b6116b28487613f7e565b90508092506116c18187613f56565b91506107d181116116da575060009150819050806116e9565b6116e66103e982614918565b90505b93509350939050565b604051631e1c6a0760e01b81526001600160a01b038781166004830152600091829189917f0000000000000000000000007e05363e225c1c8096b1cd233b59457104b8490890911690631e1c6a0790602401602060405180830381865afa158015611761573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061178591906148ab565b6117a2576040516392c46cf760e01b815260040160405180910390fd5b6117b76001600160a01b038a1633308a613a58565b604051635ab6755360e11b8152600481018890526001600160a01b038981166024830152604482018890526064820187905260c06084830152600060c483015260a482018690528a169063b56ceaa69060e40160408051808303816000875af1158015611828573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061184c91906149a8565b9250925050965096945050505050565b6000818042111561188057604051630992d5df60e41b815260040160405180910390fd5b604051631e1c6a0760e01b81526001600160a01b03808916600483015288917f0000000000000000000000007e05363e225c1c8096b1cd233b59457104b8490890911690631e1c6a0790602401602060405180830381865afa1580156118ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061190e91906148ab565b61192b576040516392c46cf760e01b815260040160405180910390fd5b7f00000000000000000000000043000000000000000000000000000000000000046001600160a01b0316886001600160a01b031663d4b970466040518163ffffffff1660e01b8152600401602060405180830381865afa158015611993573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119b791906148c8565b6001600160a01b0316146119de5760405163807af6e560e01b815260040160405180910390fd5b611a223389888b6001600160a01b0316634a248d2a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ee1573d6000803e3d6000fd5b610f21883087613f24565b6000803068929eee149b4bd212685403611a4f5763ab143c066000526004601cfd5b604051631e1c6a0760e01b81526001600160a01b03808616600483015285917f0000000000000000000000007e05363e225c1c8096b1cd233b59457104b8490890911690631e1c6a0790602401602060405180830381865afa158015611ab9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611add91906148ab565b611afa576040516392c46cf760e01b815260040160405180910390fd5b6000611b7186876001600160a01b0316634a248d2a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b6291906148c8565b6001600160a01b031690613d82565b90506000611bb787886001600160a01b031663d4b970466040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b3e573d6000803e3d6000fd5b90506000876001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611bf9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c1d919061493e565b905080611c2a88856149cc565b611c3491906149e3565b955080611c4188846149cc565b611c4b91906149e3565b9450505050509250929050565b60008180421115611c7c57604051630992d5df60e41b815260040160405180910390fd5b604051631e1c6a0760e01b81526001600160a01b03808a16600483015289917f0000000000000000000000007e05363e225c1c8096b1cd233b59457104b8490890911690631e1c6a0790602401602060405180830381865afa158015611ce6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d0a91906148ab565b611d27576040516392c46cf760e01b815260040160405180910390fd5b6000896001600160a01b0316634a248d2a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d67573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d8b91906148c8565b905060008a6001600160a01b031663d4b970466040518163ffffffff1660e01b8152600401602060405180830381865afa158015611dcd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611df191906148c8565b9050611e086001600160a01b038c1633308b613a58565b604051635ab6755360e11b8152600481018990523060248201526000604482018190526064820181905260c0608483015260c4820181905260a482018890529081906001600160a01b038e169063b56ceaa69060e40160408051808303816000875af1158015611e7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ea091906149a8565b915091508a15611f5357611ebe6001600160a01b0384168e83613c93565b604051636ec9facd60e11b81523060048201526001600160a01b038e169063dd93f59a906024016020604051808303816000875af1158015611f04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f28919061493e565b611f32908361492b565b96508615611f4e57611f4e6001600160a01b0385168d89613c93565b611ff7565b611f676001600160a01b0385168e84613c93565b604051632f58056d60e21b81523060048201526001600160a01b038e169063bd6015b4906024016020604051808303816000875af1158015611fad573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fd1919061493e565b611fdb908261492b565b96508615611ff757611ff76001600160a01b0384168d89613c93565b8887101561202057604051632ff97dcd60e11b8152600481018890526024015b60405180910390fd5b5050505050509695505050505050565b6000818042111561205457604051630992d5df60e41b815260040160405180910390fd5b604051631e1c6a0760e01b81526001600160a01b03808916600483015288917f0000000000000000000000007e05363e225c1c8096b1cd233b59457104b8490890911690631e1c6a0790602401602060405180830381865afa1580156120be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120e291906148ab565b6120ff576040516392c46cf760e01b815260040160405180910390fd5b6000886001600160a01b0316634a248d2a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561213f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061216391906148c8565b90507f00000000000000000000000043000000000000000000000000000000000000046001600160a01b0316816001600160a01b03160361220757886001600160a01b031663d4b970466040518163ffffffff1660e01b8152600401602060405180830381865afa1580156121dc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061220091906148c8565b90506122ba565b7f00000000000000000000000043000000000000000000000000000000000000046001600160a01b0316896001600160a01b031663d4b970466040518163ffffffff1660e01b8152600401602060405180830381865afa15801561226f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061229391906148c8565b6001600160a01b0316146122ba57604051639700d1eb60e01b815260040160405180910390fd5b7f00000000000000000000000043000000000000000000000000000000000000046001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561231557600080fd5b505af1158015612329573d6000803e3d6000fd5b506123659350506001600160a01b037f00000000000000000000000043000000000000000000000000000000000000041691508b905034613c93565b61237a6001600160a01b038216338b8a613a58565b612385898988613ce2565b9998505050505050505050565b600081804211156123b657604051630992d5df60e41b815260040160405180910390fd5b6123c08787613f93565b6000878760008181106123d5576123d5614a05565b90506020020160208101906123ea919061488e565b905060008660011660000361246257816001600160a01b0316634a248d2a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612437573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061245b91906148c8565b90506124c7565b816001600160a01b031663d4b970466040518163ffffffff1660e01b8152600401602060405180830381865afa1580156124a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124c491906148c8565b90505b7f00000000000000000000000043000000000000000000000000000000000000046001600160a01b0316816001600160a01b0316146125195760405163b1e72b7960e01b815260040160405180910390fd5b7f00000000000000000000000043000000000000000000000000000000000000046001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561257457600080fd5b505af1158015612588573d6000803e3d6000fd5b506125a3935050506001600160a01b03831690508334613c93565b6125b08a8a8a8a8a613fd8565b9a9950505050505050505050565b600080600083804211156125e557604051630992d5df60e41b815260040160405180910390fd5b604051631e1c6a0760e01b81526001600160a01b03808d1660048301528c917f0000000000000000000000007e05363e225c1c8096b1cd233b59457104b8490890911690631e1c6a0790602401602060405180830381865afa15801561264f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061267391906148ab565b612690576040516392c46cf760e01b815260040160405180910390fd5b60008c6001600160a01b0316634a248d2a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156126d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126f491906148c8565b905060008d6001600160a01b031663d4b970466040518163ffffffff1660e01b8152600401602060405180830381865afa158015612736573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061275a91906148c8565b90508b15612808576127776001600160a01b03831633308e613a58565b6127818a8c614918565b96506127976001600160a01b0383168f8c613c93565b604051632f58056d60e21b81523060048201526001600160a01b038f169063bd6015b4906024016020604051808303816000875af11580156127dd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612801919061493e565b95506128aa565b61281d6001600160a01b03821633308e613a58565b6128278a8c614918565b955061283d6001600160a01b0382168f8c613c93565b604051636ec9facd60e11b81523060048201526001600160a01b038f169063dd93f59a906024016020604051808303816000875af1158015612883573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128a7919061493e565b96505b6128b58e8888613ab5565b90975095506128ce6001600160a01b0383168f89613c93565b6128e26001600160a01b0382168f88613c93565b6128ed8e8e8b613ce2565b945060006129046001600160a01b03841630613d82565b90508015612920576129206001600160a01b0384163383613c93565b6129336001600160a01b03831630613d82565b9050801561294f5761294f6001600160a01b0383163383613c93565b50505050509750975097945050505050565b6000818042111561298557604051630992d5df60e41b815260040160405180910390fd5b604051631e1c6a0760e01b81526001600160a01b03808a16600483015289917f0000000000000000000000007e05363e225c1c8096b1cd233b59457104b8490890911690631e1c6a0790602401602060405180830381865afa1580156129ef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a1391906148ab565b612a30576040516392c46cf760e01b815260040160405180910390fd5b612a74338a898c6001600160a01b0316634a248d2a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ee1573d6000803e3d6000fd5b612ab8338a888c6001600160a01b031663d4b970466040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ee1573d6000803e3d6000fd5b612385898987613ce2565b60008180421115612ae757604051630992d5df60e41b815260040160405180910390fd5b612af18787613f93565b6000612afe600188614918565b90506000888883818110612b1457612b14614a05565b9050602002016020810190612b29919061488e565b90506000600188841c168103612ba257816001600160a01b031663d4b970466040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b77573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b9b91906148c8565b9050612c07565b816001600160a01b0316634a248d2a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612be0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c0491906148c8565b90505b7f00000000000000000000000043000000000000000000000000000000000000046001600160a01b0316816001600160a01b031614612c59576040516365ba5f2960e01b815260040160405180910390fd5b60008a8a6000818110612c6e57612c6e614a05565b9050602002016020810190612c83919061488e565b905088600116600003612cd957612cd433828e846001600160a01b0316634a248d2a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ee1573d6000803e3d6000fd5b612d1d565b612d1d33828e846001600160a01b031663d4b970466040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ee1573d6000803e3d6000fd5b612d2a308c8c8c8c613fd8565b604051632e1a7d4d60e01b8152600481018290529096507f00000000000000000000000043000000000000000000000000000000000000046001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015612d8f57600080fd5b505af1158015612da3573d6000803e3d6000fd5b50612dbb925050506001600160a01b038e1687613f04565b5050505050979650505050505050565b60008180421115612def57604051630992d5df60e41b815260040160405180910390fd5b604051631e1c6a0760e01b81526001600160a01b03808916600483015288917f0000000000000000000000007e05363e225c1c8096b1cd233b59457104b8490890911690631e1c6a0790602401602060405180830381865afa158015612e59573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e7d91906148ab565b612e9a576040516392c46cf760e01b815260040160405180910390fd5b612ede3389888b6001600160a01b0316634a248d2a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ee1573d6000803e3d6000fd5b611563888887613f24565b60008180421115612f0d57604051630992d5df60e41b815260040160405180910390fd5b604051631e1c6a0760e01b81526001600160a01b03808816600483015287917f0000000000000000000000007e05363e225c1c8096b1cd233b59457104b8490890911690631e1c6a0790602401602060405180830381865afa158015612f77573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f9b91906148ab565b612fb8576040516392c46cf760e01b815260040160405180910390fd5b6000876001600160a01b031663d4b970466040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ff8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061301c91906148c8565b90507f00000000000000000000000043000000000000000000000000000000000000046001600160a01b0316816001600160a01b0316146130705760405163807af6e560e01b815260040160405180910390fd5b7f00000000000000000000000043000000000000000000000000000000000000046001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b1580156130cb57600080fd5b505af11580156130df573d6000803e3d6000fd5b506130fa935050506001600160a01b03831690508934613c93565b611563888888613e6d565b60008060003068929eee149b4bd2126854036131295763ab143c066000526004601cfd5b3068929eee149b4bd2126855838042111561315757604051630992d5df60e41b815260040160405180910390fd5b604051631e1c6a0760e01b81526001600160a01b03808c1660048301528b917f0000000000000000000000007e05363e225c1c8096b1cd233b59457104b8490890911690631e1c6a0790602401602060405180830381865afa1580156131c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131e591906148ab565b613202576040516392c46cf760e01b815260040160405180910390fd5b60008060008d6001600160a01b0316634a248d2a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613245573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061326991906148c8565b90507f00000000000000000000000043000000000000000000000000000000000000046001600160a01b0316816001600160a01b031603613323578d6001600160a01b031663d4b970466040518163ffffffff1660e01b8152600401602060405180830381865afa1580156132e2573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061330691906148c8565b90506133138e348d613ab5565b90985096508792508691506133f1565b7f00000000000000000000000043000000000000000000000000000000000000046001600160a01b03168e6001600160a01b031663d4b970466040518163ffffffff1660e01b8152600401602060405180830381865afa15801561338b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133af91906148c8565b6001600160a01b0316036133d8576133c88e8c34613ab5565b90985096508692508791506133f1565b604051639700d1eb60e01b815260040160405180910390fd5b7f00000000000000000000000043000000000000000000000000000000000000046001600160a01b031663d0e30db0846040518263ffffffff1660e01b81526004016000604051808303818588803b15801561344c57600080fd5b505af1158015613460573d6000803e3d6000fd5b50505050506134a38e847f00000000000000000000000043000000000000000000000000000000000000046001600160a01b0316613c939092919063ffffffff16565b823411156134c8576134c86134b88434614918565b6001600160a01b038e1690613f04565b6134e8338f84846001600160a01b0316613a58909392919063ffffffff16565b6134f38e8e8c613ce2565b955050505050503868929eee149b4bd212685596509650969350505050565b6000818042111561353657604051630992d5df60e41b815260040160405180910390fd5b6135408787613f93565b60008787600081811061355557613555614a05565b905060200201602081019061356a919061488e565b9050856001166000036135c0576135bb33828b846001600160a01b0316634a248d2a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ee1573d6000803e3d6000fd5b613604565b61360433828b846001600160a01b031663d4b970466040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ee1573d6000803e3d6000fd5b6125b08a89898989613fd8565b604051631e1c6a0760e01b81526001600160a01b038781166004830152600091829189917f0000000000000000000000007e05363e225c1c8096b1cd233b59457104b8490890911690631e1c6a0790602401602060405180830381865afa158015613680573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136a491906148ab565b6136c1576040516392c46cf760e01b815260040160405180910390fd5b6136d66001600160a01b038a1633308a613a58565b6000896001600160a01b0316634a248d2a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613716573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061373a91906148c8565b90507f00000000000000000000000043000000000000000000000000000000000000046001600160a01b0316816001600160a01b03160361387757896001600160a01b031663d4b970466040518163ffffffff1660e01b8152600401602060405180830381865afa1580156137b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137d791906148c8565b604051635ab6755360e11b8152600481018a9052306024820152604481018990526064810188905260c06084820152600060c482015260a481018790529091506001600160a01b038b169063b56ceaa69060e40160408051808303816000875af1158015613849573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061386d91906149a8565b90945092506139a9565b7f00000000000000000000000043000000000000000000000000000000000000046001600160a01b03168a6001600160a01b031663d4b970466040518163ffffffff1660e01b8152600401602060405180830381865afa1580156138df573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061390391906148c8565b6001600160a01b0316036133d857604051635ab6755360e11b815260048101899052306024820152604481018790526064810188905260c06084820152600060c482015260a481018690526001600160a01b038b169063b56ceaa69060e40160408051808303816000875af1158015613980573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139a491906149a8565b945092505b604051632e1a7d4d60e01b8152600481018590527f00000000000000000000000043000000000000000000000000000000000000046001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015613a0b57600080fd5b505af1158015613a1f573d6000803e3d6000fd5b50613a37925050506001600160a01b038a1685613f04565b613a4b6001600160a01b0382168a85613c93565b5050965096945050505050565b60405181606052826040528360601b602c526f23b872dd000000000000000000000000600c52602060006064601c6000895af13d156001600051141716613aa757637939f4246000526004601cfd5b600060605260405250505050565b600080846001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613af6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b1a919061493e565b600003613bc1576000856001600160a01b031663f811d6926040518163ffffffff1660e01b8152600401602060405180830381865afa158015613b61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b85919061493e565b90506000613b938683613f56565b8510613b9f5785613ba9565b613ba98583613f7e565b9050809350613bb88183613f56565b92505050613c8b565b600080866001600160a01b0316630902f1ac6040518163ffffffff1660e01b81526004016040805180830381865afa158015613c01573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c2591906149a8565b91509150600081118015613c395750600082115b15613c88576000613c4a8784613f7e565b90506000613c588784613f7e565b9050808211613c7557879550613c6e8383613f56565b9450613c85565b869450613c828482613f56565b95505b50505b50505b935093915050565b81601452806034526fa9059cbb00000000000000000000000060005260206000604460106000875af13d156001600051141716613cd8576390b8ec186000526004601cfd5b6000603452505050565b604051634c85b42560e01b81526001600160a01b03838116600483015260009190851690634c85b425906024016060604051808303816000875af1158015613d2e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d52919061497a565b509091505081811015613d7b57604051632ff97dcd60e11b815260048101829052602401612017565b9392505050565b6000816014526f70a0823100000000000000000000000060005260208060246010865afa601f3d111660205102905092915050565b60ff82161580613dc8575060ff8116155b15613de65760405163ca1aefb560e01b815260040160405180910390fd5b60128260ff161180613dfb575060128160ff16115b15613e195760405163062d0f8560e51b815260040160405180910390fd5b60008160ff168360ff1611613e3757613e328383614a1b565b613e41565b613e418284614a1b565b60ff169050600c811115613e68576040516397088e6160e01b815260040160405180910390fd5b505050565b604051636ec9facd60e11b81526001600160a01b0383811660048301526000919085169063dd93f59a906024015b6020604051808303816000875af1158015613eba573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ede919061493e565b905081811015613d7b57604051632ff97dcd60e11b815260048101829052602401612017565b60003860003884865af1613f205763b12d13eb6000526004601cfd5b5050565b604051632f58056d60e21b81526001600160a01b0383811660048301526000919085169063bd6015b490602401613e9b565b6000670de0b6b3a7640000613f6b83856149cc565b613f7591906149e3565b90505b92915050565b600081613f6b670de0b6b3a7640000856149cc565b80610100811115613fb7576040516315e8dba360e01b815260040160405180910390fd5b60008111613e68576040516376ede79b60e11b815260040160405180910390fd5b600080613fe6600186614918565b905060005b8181101561423c57600087878381811061400757614007614a05565b905060200201602081019061401c919061488e565b604051631e1c6a0760e01b81526001600160a01b0380831660048301529192507f0000000000000000000000007e05363e225c1c8096b1cd233b59457104b8490890911690631e1c6a0790602401602060405180830381865afa158015614087573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140ab91906148ab565b6140c8576040516392c46cf760e01b815260040160405180910390fd5b85600116600003614183576001600160a01b03811663bd6015b489896140ef86600161492b565b8181106140fe576140fe614a05565b9050602002016020810190614113919061488e565b6040516001600160e01b031960e084901b1681526001600160a01b0390911660048201526024016020604051808303816000875af1158015614159573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061417d919061493e565b5061422f565b6001600160a01b03811663dd93f59a898961419f86600161492b565b8181106141ae576141ae614a05565b90506020020160208101906141c3919061488e565b6040516001600160e01b031960e084901b1681526001600160a01b0390911660048201526024016020604051808303816000875af1158015614209573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061422d919061493e565b505b50600194851c9401613feb565b50836001166000036142e45785858281811061425a5761425a614a05565b905060200201602081019061426f919061488e565b604051632f58056d60e21b81526001600160a01b038981166004830152919091169063bd6015b4906024016020604051808303816000875af11580156142b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142dd919061493e565b915061437c565b8585828181106142f6576142f6614a05565b905060200201602081019061430b919061488e565b604051636ec9facd60e11b81526001600160a01b038981166004830152919091169063dd93f59a906024016020604051808303816000875af1158015614355573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614379919061493e565b91505b828210156143a057604051632ff97dcd60e11b815260048101839052602401612017565b5095945050505050565b600061010082840312156143bd57600080fd5b50919050565b6001600160a01b03811681146143d857600080fd5b50565b80151581146143d857600080fd5b600080600080600080600080610100898b03121561440657600080fd5b8835614411816143c3565b97506020890135614421816143db565b965060408901359550606089013594506080890135935060a0890135614446816143c3565b925060c0890135915060e089013561445d816143db565b809150509295985092959890939650565b600080600080600060a0868803121561448657600080fd5b8535614491816143c3565b945060208601356144a1816143c3565b94979496505050506040830135926060810135926080909101359150565b60008060008060008060008060006101208a8c0312156144de57600080fd5b89356144e9816143c3565b985060208a01356144f9816143c3565b975060408a0135965060608a0135955060808a0135945060a08a013561451e816143c3565b935060c08a0135925060e08a013591506101008a013561453d816143db565b809150509295985092959850929598565b60008060008060008060c0878903121561456757600080fd5b8635614572816143c3565b95506020870135614582816143c3565b95989597505050506040840135936060810135936080820135935060a0909101359150565b600080600080608085870312156145bd57600080fd5b84356145c8816143c3565b935060208501356145d8816143c3565b93969395505050506040820135916060013590565b60008060006060848603121561460257600080fd5b505081359360208301359350604090920135919050565b6000806040838503121561462c57600080fd5b8235614637816143c3565b946020939093013593505050565b60008060008060008060c0878903121561465e57600080fd5b8635614669816143c3565b95506020870135614679816143c3565b94506040870135614689816143db565b959894975094956060810135955060808101359460a0909101359350915050565b60008083601f8401126146bc57600080fd5b50813567ffffffffffffffff8111156146d457600080fd5b6020830191508360208260051b85010111156146ef57600080fd5b9250929050565b60008060008060008060a0878903121561470f57600080fd5b863561471a816143c3565b9550602087013567ffffffffffffffff81111561473657600080fd5b61474289828a016146aa565b979a90995096976040810135976060820135975060809091013595509350505050565b600080600080600080600060e0888a03121561478057600080fd5b873561478b816143c3565b9650602088013561479b816143c3565b955060408801356147ab816143db565b969995985095966060810135965060808101359560a0820135955060c0909101359350915050565b600080600080600080600060c0888a0312156147ee57600080fd5b87356147f9816143c3565b965060208801359550604088013567ffffffffffffffff81111561481c57600080fd5b6148288a828b016146aa565b989b979a50986060810135976080820135975060a09091013595509350505050565b60008060008060008060c0878903121561486357600080fd5b863561486e816143c3565b9550602087013561487e816143c3565b94506040870135614689816143c3565b6000602082840312156148a057600080fd5b8135613d7b816143c3565b6000602082840312156148bd57600080fd5b8151613d7b816143db565b6000602082840312156148da57600080fd5b8151613d7b816143c3565b6000602082840312156148f757600080fd5b8135613d7b816143db565b634e487b7160e01b600052601160045260246000fd5b81810381811115613f7857613f78614902565b80820180821115613f7857613f78614902565b60006020828403121561495057600080fd5b5051919050565b60006020828403121561496957600080fd5b815160ff81168114613d7b57600080fd5b60008060006060848603121561498f57600080fd5b8351925060208401519150604084015190509250925092565b600080604083850312156149bb57600080fd5b505080516020909101519092909150565b8082028115828204841417613f7857613f78614902565b600082614a0057634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052603260045260246000fd5b60ff8281168282160390811115613f7857613f7861490256fea264697066735822122045228d232f7c69682bdc5876b4908b5797bead31ed44859911d15aa1e5911a6664736f6c63430008140033

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

00000000000000000000000043000000000000000000000000000000000000040000000000000000000000007e05363e225c1c8096b1cd233b59457104b84908000000000000000000000000d69e75c1c2a0f2838a6bba8bdff9d08c8f137cd9

-----Decoded View---------------
Arg [0] : weth_ (address): 0x4300000000000000000000000000000000000004
Arg [1] : factory (address): 0x7E05363E225c1c8096b1cd233B59457104B84908
Arg [2] : governor_ (address): 0xD69E75C1c2a0f2838A6bbA8BDFf9d08C8f137cD9

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 0000000000000000000000004300000000000000000000000000000000000004
Arg [1] : 0000000000000000000000007e05363e225c1c8096b1cd233b59457104b84908
Arg [2] : 000000000000000000000000d69e75c1c2a0f2838a6bba8bdff9d08c8f137cd9


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
[ 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.