ETH Price: $1,972.36 (+0.13%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

More Info

Private Name Tags

ContractCreator

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Multicall245101522026-02-22 4:55:234 hrs ago1771736123IN
0x00000000...925F600e4
0.01 ETH0.000004960.03082203
Multicall245098822026-02-22 4:01:235 hrs ago1771732883IN
0x00000000...925F600e4
0.5 ETH0.000041180.10965007
Multicall245098182026-02-22 3:48:355 hrs ago1771732115IN
0x00000000...925F600e4
0.01 ETH0.000053520.11036422
Multicall245097782026-02-22 3:40:355 hrs ago1771731635IN
0x00000000...925F600e4
0.05 ETH0.000720422.03245434
Multicall245093732026-02-22 2:18:596 hrs ago1771726739IN
0x00000000...925F600e4
0.05078558 ETH0.000147360.801839
Multicall245087632026-02-22 0:16:239 hrs ago1771719383IN
0x00000000...925F600e4
0.0005 ETH0.000017220.11140654
Multicall245087232026-02-22 0:08:239 hrs ago1771718903IN
0x00000000...925F600e4
0.0005 ETH0.000017060.11122364
Multicall245080382026-02-21 21:50:1111 hrs ago1771710611IN
0x00000000...925F600e4
0.0005 ETH0.000005890.03576708
Multicall245074662026-02-21 19:55:1113 hrs ago1771703711IN
0x00000000...925F600e4
0.0005 ETH0.000017450.12015945
Multicall245074522026-02-21 19:52:1113 hrs ago1771703531IN
0x00000000...925F600e4
0.0005 ETH0.000017760.11755359
Multicall245071662026-02-21 18:54:3514 hrs ago1771700075IN
0x00000000...925F600e4
0 ETH0.000003260.03870162
Multicall245069542026-02-21 18:12:1115 hrs ago1771697531IN
0x00000000...925F600e4
0.0005 ETH0.000006310.04170207
Multicall245069302026-02-21 18:07:2315 hrs ago1771697243IN
0x00000000...925F600e4
0.03928469 ETH0.000104750.81239941
Multicall245069282026-02-21 18:06:5915 hrs ago1771697219IN
0x00000000...925F600e4
0.03927673 ETH0.000134430.81339711
Multicall245067792026-02-21 17:37:1115 hrs ago1771695431IN
0x00000000...925F600e4
0.012345 ETH0.000383290.81216489
Ensure Allowance245061102026-02-21 15:22:5917 hrs ago1771687379IN
0x00000000...925F600e4
0 ETH0.000002470.04773296
Multicall245055822026-02-21 13:36:5919 hrs ago1771681019IN
0x00000000...925F600e4
0.0005 ETH0.000332652.04875765
Multicall245053642026-02-21 12:53:2320 hrs ago1771678403IN
0x00000000...925F600e4
0.00177514 ETH0.000021950.04380956
Multicall245053132026-02-21 12:43:1120 hrs ago1771677791IN
0x00000000...925F600e4
0.00005518 ETH0.000016880.04497509
Multicall245052992026-02-21 12:40:2320 hrs ago1771677623IN
0x00000000...925F600e4
0.00458729 ETH0.000020710.04133074
Multicall245052502026-02-21 12:30:3520 hrs ago1771677035IN
0x00000000...925F600e4
0 ETH0.000518250.81679409
Multicall245047852026-02-21 10:57:1122 hrs ago1771671431IN
0x00000000...925F600e4
0.0005 ETH0.000005580.03722065
Multicall245044532026-02-21 9:50:3523 hrs ago1771667435IN
0x00000000...925F600e4
0 ETH0.000004940.04291891
Multicall245042792026-02-21 9:15:3524 hrs ago1771665335IN
0x00000000...925F600e4
0 ETH0.000006970.06318228
Multicall245040432026-02-21 8:27:5924 hrs ago1771662479IN
0x00000000...925F600e4
0 ETH0.000016390.14242994
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Method Block
From
To
Reveal245101522026-02-22 4:55:234 hrs ago1771736123
0x00000000...925F600e4
0.01 ETH
Swap Exact In245098822026-02-22 4:01:235 hrs ago1771732883
0x00000000...925F600e4
0.5 ETH
Swap Exact In245098182026-02-22 3:48:355 hrs ago1771732115
0x00000000...925F600e4
0.01 ETH
Swap Exact In245097782026-02-22 3:40:355 hrs ago1771731635
0x00000000...925F600e4
0.05 ETH
Transfer245093732026-02-22 2:18:596 hrs ago1771726739
0x00000000...925F600e4
0.00025266 ETH
Transfer245093732026-02-22 2:18:596 hrs ago1771726739
0x00000000...925F600e4
0.05053292 ETH
Reveal245087632026-02-22 0:16:239 hrs ago1771719383
0x00000000...925F600e4
0.0005 ETH
Reveal245087232026-02-22 0:08:239 hrs ago1771718903
0x00000000...925F600e4
0.0005 ETH
Reveal245080382026-02-21 21:50:1111 hrs ago1771710611
0x00000000...925F600e4
0.0005 ETH
Reveal245074662026-02-21 19:55:1113 hrs ago1771703711
0x00000000...925F600e4
0.0005 ETH
Reveal245074522026-02-21 19:52:1113 hrs ago1771703531
0x00000000...925F600e4
0.0005 ETH
Reveal245069542026-02-21 18:12:1115 hrs ago1771697531
0x00000000...925F600e4
0.0005 ETH
Transfer245069302026-02-21 18:07:2315 hrs ago1771697243
0x00000000...925F600e4
0.00019544 ETH
Transfer*245069302026-02-21 18:07:2315 hrs ago1771697243
0x00000000...925F600e4
0.03908924 ETH
Transfer245069282026-02-21 18:06:5915 hrs ago1771697219
0x00000000...925F600e4
0.03909512 ETH
Transfer*245067792026-02-21 17:37:1115 hrs ago1771695431
0x00000000...925F600e4
0.012345 ETH
Reveal245055822026-02-21 13:36:5919 hrs ago1771681019
0x00000000...925F600e4
0.0005 ETH
Swap Exact In245053642026-02-21 12:53:2320 hrs ago1771678403
0x00000000...925F600e4
0.00177514 ETH
Swap Exact In245053132026-02-21 12:43:1120 hrs ago1771677791
0x00000000...925F600e4
0.00005518 ETH
Swap Exact In245052992026-02-21 12:40:2320 hrs ago1771677623
0x00000000...925F600e4
0.00458729 ETH
Swap Exact In245052502026-02-21 12:30:3520 hrs ago1771677035
0x00000000...925F600e4
0.02226339 ETH
Transfer245052502026-02-21 12:30:3520 hrs ago1771677035
0x00000000...925F600e4
0.02226339 ETH
Reveal245047852026-02-21 10:57:1122 hrs ago1771671431
0x00000000...925F600e4
0.0005 ETH
Reveal245022622026-02-21 2:30:4730 hrs ago1771641047
0x00000000...925F600e4
0.0005 ETH
Reveal245022622026-02-21 2:30:4730 hrs ago1771641047
0x00000000...925F600e4
0.0005 ETH
View All Internal Transactions
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
zRouter

Compiler Version
v0.8.33+commit.64118f21

Optimization Enabled:
Yes with 9999999 runs

Other Settings:
prague EvmVersion
File 1 of 1 : zRouter.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.33;

/// @dev uniV2 / uniV3 / uniV4 / zAMM
///      multi-amm multi-call router
///      optimized with simple abi.
///      Includes trusted routers,
///      and a Curve AMM swapper,
///      as well as Lido staker,
///      and generic executor.
contract zRouter {
    error BadSwap();
    error Expired();
    error Slippage();
    error InvalidId();
    error Unauthorized();
    error InvalidMsgVal();
    error SwapExactInFail();
    error SwapExactOutFail();
    error ETHTransferFailed();
    error SnwapSlippage(address token, uint256 received, uint256 minimum);

    SafeExecutor public immutable safeExecutor;

    modifier checkDeadline(uint256 deadline) {
        require(block.timestamp <= deadline, Expired());
        _;
    }

    event OwnershipTransferred(address indexed from, address indexed to);

    constructor() payable {
        safeExecutor = new SafeExecutor();
        safeApprove(STETH, WSTETH, type(uint256).max); // lido
        emit OwnershipTransferred(address(0), _owner = tx.origin);
    }

    function swapV2(
        address to,
        bool exactOut,
        address tokenIn,
        address tokenOut,
        uint256 swapAmount,
        uint256 amountLimit,
        uint256 deadline
    ) public payable checkDeadline(deadline) returns (uint256 amountIn, uint256 amountOut) {
        bool ethIn = tokenIn == address(0);
        bool ethOut = tokenOut == address(0);

        if (ethIn) tokenIn = WETH;
        if (ethOut) tokenOut = WETH;

        bool sushiSwap;
        unchecked {
            if (deadline == type(uint256).max) {
                (sushiSwap, deadline) = (true, block.timestamp + 30 minutes);
            }
        }

        (address pool, bool zeroForOne) = _v2PoolFor(tokenIn, tokenOut, sushiSwap);
        (uint112 r0, uint112 r1,) = IV2Pool(pool).getReserves();
        (uint256 resIn, uint256 resOut) = zeroForOne ? (r0, r1) : (r1, r0);

        unchecked {
            if (exactOut) {
                amountOut = swapAmount; // target
                uint256 n = resIn * amountOut * 1000;
                uint256 d = (resOut - amountOut) * 997;
                amountIn = (n + d - 1) / d; // ceil-div
                require(amountLimit == 0 || amountIn <= amountLimit, Slippage());
            } else {
                if (swapAmount == 0) {
                    amountIn = ethIn ? msg.value : balanceOf(tokenIn);
                    if (amountIn == 0) revert BadSwap();
                } else {
                    amountIn = swapAmount;
                }
                amountOut = (amountIn * 997 * resOut) / (resIn * 1000 + amountIn * 997);
                require(amountLimit == 0 || amountOut >= amountLimit, Slippage());
            }
            if (!_useTransientBalance(pool, tokenIn, 0, amountIn)) {
                if (_useTransientBalance(address(this), tokenIn, 0, amountIn)) {
                    safeTransfer(tokenIn, pool, amountIn);
                } else if (ethIn) {
                    wrapETH(pool, amountIn);
                    if (to != address(this)) {
                        if (msg.value > amountIn) {
                            _safeTransferETH(msg.sender, msg.value - amountIn);
                        }
                    }
                } else {
                    safeTransferFrom(tokenIn, msg.sender, pool, amountIn);
                }
            }
        }

        if (zeroForOne) {
            IV2Pool(pool).swap(0, amountOut, ethOut ? address(this) : to, "");
        } else {
            IV2Pool(pool).swap(amountOut, 0, ethOut ? address(this) : to, "");
        }

        if (ethOut) {
            unwrapETH(amountOut);
            _safeTransferETH(to, amountOut);
        } else {
            depositFor(tokenOut, 0, amountOut, to); // marks output target
        }
    }

    function swapV3(
        address to,
        bool exactOut,
        uint24 swapFee,
        address tokenIn,
        address tokenOut,
        uint256 swapAmount,
        uint256 amountLimit,
        uint256 deadline
    ) public payable checkDeadline(deadline) returns (uint256 amountIn, uint256 amountOut) {
        bool ethIn = tokenIn == address(0);
        bool ethOut = tokenOut == address(0);

        if (ethIn) tokenIn = WETH;
        if (ethOut) tokenOut = WETH;

        (address pool, bool zeroForOne) = _v3PoolFor(tokenIn, tokenOut, swapFee);
        uint160 sqrtPriceLimitX96 = zeroForOne ? MIN_SQRT_RATIO_PLUS_ONE : MAX_SQRT_RATIO_MINUS_ONE;

        unchecked {
            if (!exactOut && swapAmount == 0) {
                swapAmount = ethIn ? msg.value : balanceOf(tokenIn);
                if (swapAmount == 0) revert BadSwap();
            }
            (int256 a0, int256 a1) = IV3Pool(pool)
                .swap(
                    ethOut ? address(this) : to,
                    zeroForOne,
                    exactOut ? -(int256(swapAmount)) : int256(swapAmount),
                    sqrtPriceLimitX96,
                    abi.encodePacked(ethIn, ethOut, msg.sender, tokenIn, tokenOut, to, swapFee)
                );

            if (amountLimit != 0) {
                if (exactOut) require(uint256(zeroForOne ? a0 : a1) <= amountLimit, Slippage());
                else require(uint256(-(zeroForOne ? a1 : a0)) >= amountLimit, Slippage());
            }

            // ── return values ────────────────────────────────
            // ── translate pool deltas to user-facing amounts ─
            (int256 dIn, int256 dOut) = zeroForOne ? (a0, a1) : (a1, a0);
            amountIn = dIn >= 0 ? uint256(dIn) : uint256(-dIn);
            amountOut = dOut <= 0 ? uint256(-dOut) : uint256(dOut);

            // Handle ETH input refund (separate from output tracking)
            if (ethIn) {
                if ((swapAmount = address(this).balance) != 0 && to != address(this)) {
                    _safeTransferETH(msg.sender, swapAmount);
                }
            }
            // Handle output tracking for chaining (must always run when !ethOut)
            if (!ethOut) {
                depositFor(tokenOut, 0, amountOut, to);
            }
        }
    }

    /// @dev `uniswapV3SwapCallback`.
    fallback() external payable {
        assembly ("memory-safe") {
            if gt(tload(0x00), 0) { revert(0, 0) }
        }
        unchecked {
            int256 amount0Delta;
            int256 amount1Delta;
            bool ethIn;
            bool ethOut;
            address payer;
            address tokenIn;
            address tokenOut;
            address to;
            uint24 swapFee;
            assembly ("memory-safe") {
                amount0Delta := calldataload(0x4)
                amount1Delta := calldataload(0x24)
                ethIn := byte(0, calldataload(0x84))
                ethOut := byte(0, calldataload(add(0x84, 1)))
                payer := shr(96, calldataload(add(0x84, 2)))
                tokenIn := shr(96, calldataload(add(0x84, 22)))
                tokenOut := shr(96, calldataload(add(0x84, 42)))
                to := shr(96, calldataload(add(0x84, 62)))
                swapFee := and(shr(232, calldataload(add(0x84, 82))), 0xFFFFFF)
            }
            require(amount0Delta != 0 || amount1Delta != 0, BadSwap());
            (address pool, bool zeroForOne) = _v3PoolFor(tokenIn, tokenOut, swapFee);
            require(msg.sender == pool, Unauthorized());
            uint256 amountRequired = uint256(zeroForOne ? amount0Delta : amount1Delta);

            if (_useTransientBalance(address(this), tokenIn, 0, amountRequired)) {
                safeTransfer(tokenIn, pool, amountRequired);
            } else if (ethIn) {
                wrapETH(pool, amountRequired);
            } else {
                safeTransferFrom(tokenIn, payer, pool, amountRequired);
            }
            if (ethOut) {
                uint256 amountOut = uint256(-(zeroForOne ? amount1Delta : amount0Delta));
                unwrapETH(amountOut);
                _safeTransferETH(to, amountOut);
            }
        }
    }

    function swapV4(
        address to,
        bool exactOut,
        uint24 swapFee,
        int24 tickSpace,
        address tokenIn,
        address tokenOut,
        uint256 swapAmount,
        uint256 amountLimit,
        uint256 deadline
    ) public payable checkDeadline(deadline) returns (uint256 amountIn, uint256 amountOut) {
        if (!exactOut && swapAmount == 0) {
            swapAmount = tokenIn == address(0) ? msg.value : balanceOf(tokenIn);
            if (swapAmount == 0) revert BadSwap();
        }
        (amountIn, amountOut) = abi.decode(
            IV4PoolManager(V4_POOL_MANAGER)
                .unlock(
                    abi.encode(
                        msg.sender,
                        to,
                        exactOut,
                        swapFee,
                        tickSpace,
                        tokenIn,
                        tokenOut,
                        swapAmount,
                        amountLimit
                    )
                ),
            (uint256, uint256)
        );
        depositFor(tokenOut, 0, amountOut, to); // marks output target
    }

    /// @dev Handle V4 PoolManager swap callback - hookless default.
    function unlockCallback(bytes calldata callbackData)
        public
        payable
        returns (bytes memory result)
    {
        require(msg.sender == V4_POOL_MANAGER, Unauthorized());

        assembly ("memory-safe") {
            if gt(tload(0x00), 0) { revert(0, 0) }
        }

        (
            address payer,
            address to,
            bool exactOut,
            uint24 swapFee,
            int24 tickSpace,
            address tokenIn,
            address tokenOut,
            uint256 swapAmount,
            uint256 amountLimit
        ) = abi.decode(
            callbackData,
            (address, address, bool, uint24, int24, address, address, uint256, uint256)
        );

        bool zeroForOne = tokenIn < tokenOut;
        bool ethIn = tokenIn == address(0);

        V4PoolKey memory key = V4PoolKey(
            zeroForOne ? tokenIn : tokenOut,
            zeroForOne ? tokenOut : tokenIn,
            swapFee,
            tickSpace,
            address(0)
        );

        unchecked {
            int256 delta = _swap(swapAmount, key, zeroForOne, exactOut);
            uint256 takeAmount = zeroForOne
                ? (!exactOut
                        ? uint256(uint128(delta.amount1()))
                        : uint256(uint128(-delta.amount0())))
                : (!exactOut
                        ? uint256(uint128(delta.amount0()))
                        : uint256(uint128(-delta.amount1())));

            IV4PoolManager(msg.sender).sync(tokenIn);
            uint256 amountIn = !exactOut ? swapAmount : takeAmount;

            if (_useTransientBalance(address(this), tokenIn, 0, amountIn)) {
                if (tokenIn != address(0)) {
                    safeTransfer(
                        tokenIn,
                        msg.sender, // V4_POOL_MANAGER
                        amountIn
                    );
                }
            } else if (!ethIn) {
                safeTransferFrom(
                    tokenIn,
                    payer,
                    msg.sender, // V4_POOL_MANAGER
                    amountIn
                );
            }

            uint256 amountOut = !exactOut ? takeAmount : swapAmount;
            if (amountLimit != 0 && (exactOut ? takeAmount > amountLimit : amountOut < amountLimit))
            {
                revert Slippage();
            }

            IV4PoolManager(msg.sender)
            .settle{value: ethIn ? (exactOut ? takeAmount : swapAmount) : 0}();
            IV4PoolManager(msg.sender).take(tokenOut, to, amountOut);

            result = abi.encode(amountIn, amountOut);

            if (ethIn) {
                uint256 ethRefund = address(this).balance;
                if (ethRefund != 0 && to != address(this)) {
                    _safeTransferETH(payer, ethRefund);
                }
            }
        }
    }

    function _swap(uint256 swapAmount, V4PoolKey memory key, bool zeroForOne, bool exactOut)
        internal
        returns (int256 delta)
    {
        unchecked {
            delta = IV4PoolManager(msg.sender)
                .swap(
                    key,
                    V4SwapParams(
                        zeroForOne,
                        exactOut ? int256(swapAmount) : -int256(swapAmount),
                        zeroForOne ? MIN_SQRT_RATIO_PLUS_ONE : MAX_SQRT_RATIO_MINUS_ONE
                    ),
                    ""
                );
        }
    }

    /// @dev Pull in full and refund excess against zAMM.
    function swapVZ(
        address to,
        bool exactOut,
        uint256 feeOrHook,
        address tokenIn,
        address tokenOut,
        uint256 idIn,
        uint256 idOut,
        uint256 swapAmount,
        uint256 amountLimit,
        uint256 deadline
    ) public payable checkDeadline(deadline) returns (uint256 amountIn, uint256 amountOut) {
        (address token0, address token1, bool zeroForOne) = _sortTokens(tokenIn, tokenOut);
        (uint256 id0, uint256 id1) = tokenIn == token0 ? (idIn, idOut) : (idOut, idIn);
        PoolKey memory key = PoolKey(id0, id1, token0, token1, feeOrHook);

        bool ethIn = tokenIn == address(0);
        if (!exactOut && swapAmount == 0) {
            if (ethIn) {
                swapAmount = msg.value;
            } else if (idIn == 0) {
                swapAmount = balanceOf(tokenIn);
            } else {
                swapAmount = IERC6909(tokenIn).balanceOf(address(this), idIn);
            }
            if (swapAmount == 0) revert BadSwap();
        }
        if (!_useTransientBalance(
                address(this), tokenIn, idIn, !exactOut ? swapAmount : amountLimit
            )) {
            if (!ethIn) {
                if (idIn == 0) {
                    safeTransferFrom(
                        tokenIn, msg.sender, address(this), !exactOut ? swapAmount : amountLimit
                    );
                } else {
                    IERC6909(tokenIn)
                        .transferFrom(
                            msg.sender, address(this), idIn, !exactOut ? swapAmount : amountLimit
                        );
                }
            }
        }

        address dst = deadline != type(uint256).max ? ZAMM : ZAMM_0; // support hookless zAMM
        unchecked {
            if (dst == ZAMM_0) {
                key.feeOrHook = uint256(uint96(key.feeOrHook));
                deadline = block.timestamp + 30 minutes;
            }
        }

        uint256 swapResult;
        if (!exactOut) {
            bytes4 sel = (dst == ZAMM) ? bytes4(0x3c5eec50) : bytes4(0x7466fde7);
            bytes memory callData =
                abi.encodeWithSelector(sel, key, swapAmount, amountLimit, zeroForOne, to, deadline);
            (bool ok, bytes memory ret) = dst.call{value: ethIn ? swapAmount : 0}(callData);
            require(ok, SwapExactInFail());
            swapResult = abi.decode(ret, (uint256));
        } else {
            bytes4 sel = (dst == ZAMM) ? bytes4(0x38c3f8db) : bytes4(0xd4ff3f0e);
            bytes memory callData =
                abi.encodeWithSelector(sel, key, swapAmount, amountLimit, zeroForOne, to, deadline);
            (bool ok, bytes memory ret) = dst.call{value: ethIn ? amountLimit : 0}(callData);
            require(ok, SwapExactOutFail());
            swapResult = abi.decode(ret, (uint256));
        }

        // ── return values ────────────────────────────────
        (amountIn, amountOut) = exactOut ? (swapResult, swapAmount) : (swapAmount, swapResult);

        if (exactOut && to != address(this)) {
            uint256 refund;
            if (ethIn) {
                refund = address(this).balance;
                if (refund != 0) _safeTransferETH(msg.sender, refund);
            } else if (idIn == 0) {
                refund = balanceOf(tokenIn);
                if (refund != 0) safeTransfer(tokenIn, msg.sender, refund);
            } else {
                refund = IERC6909(tokenIn).balanceOf(address(this), idIn);
                if (refund != 0) IERC6909(tokenIn).transfer(msg.sender, idIn, refund);
            }
        } else {
            depositFor(tokenOut, idOut, amountOut, to); // marks output target
        }
    }

    function swapCurve(
        address to,
        bool exactOut,
        address[11] calldata route,
        uint256[4][5] calldata swapParams, // [i, j, swap_type, pool_type]
        address[5] calldata basePools, // for meta pools (only used by type=2 get_dx)
        uint256 swapAmount,
        uint256 amountLimit,
        uint256 deadline
    ) public payable checkDeadline(deadline) returns (uint256 amountIn, uint256 amountOut) {
        // ---- resolve last hop & output token ----
        address inputToken = route[0];
        address outputToken;
        uint256 lastIdx;
        unchecked {
            for (uint256 i; i < 5; ++i) {
                address pool = route[i * 2 + 1];
                if (pool == address(0)) break;
                outputToken = route[(i + 1) * 2];
                lastIdx = i;
            }
        }
        bool ethIn = _isETH(inputToken);

        // ---- compute working amount ----
        uint256 amount = swapAmount;
        if (exactOut) {
            // backward pass: Curve-style get_dx to find required input:
            unchecked {
                for (uint256 k = lastIdx + 1; k != 0;) {
                    uint256 i = --k;
                    address pool = route[i * 2 + 1];
                    uint256[4] memory p = swapParams[i]; // [i, j, swap_type, pool_type]
                    uint256 st = p[2];
                    uint256 pt = p[3];

                    if (st == 8) {
                        // ETH<->WETH is 1:1
                    } else if (st == 1) {
                        if (pt == 10) {
                            int128 pi = int128(int256(p[0]));
                            int128 pj = int128(int256(p[1]));
                            amount = IStableNgPool(pool).get_dx(pi, pj, amount);
                        } else {
                            amount = ICryptoNgPool(pool).get_dx(p[0], p[1], amount);
                        }
                    } else if (st == 2) {
                        int128 pi = int128(int256(p[0]));
                        int128 pj = int128(int256(p[1]));
                        if (pi > 0 && pj > 0) {
                            amount = IStableNgPool(basePools[i]).get_dx(pi - 1, pj - 1, amount);
                        } else {
                            amount = IStableNgMetaPool(pool).get_dx_underlying(pi, pj, amount);
                        }
                    } else if (st == 4) {
                        // inverse of add_liquidity (approx):
                        amount = (pt == 10)
                            ? IStableNgPool(pool)
                                .calc_withdraw_one_coin(amount, int128(int256(p[0])))
                            : ICryptoNgPool(pool).calc_withdraw_one_coin(amount, p[0]);
                    } else if (st == 6) {
                        if (pt == 10) {
                            uint256[8] memory a;
                            a[p[1]] = amount;
                            amount = IStableNgPool(pool).calc_token_amount(a, false);
                        } else if (pt == 20) {
                            uint256[2] memory a2;
                            a2[p[1]] = amount;
                            amount = ITwoCryptoNgPool(pool).calc_token_amount(a2, false);
                        } else if (pt == 30) {
                            uint256[3] memory a3;
                            a3[p[1]] = amount;
                            amount = ITriCryptoNgPool(pool).calc_token_amount(a3, false);
                        } else {
                            revert BadSwap();
                        }
                    } else {
                        revert BadSwap();
                    }
                }
            }
            amountIn = amount;
            if (amountLimit != 0 && amountIn > amountLimit) revert Slippage();
        } else {
            // exact-in flow:
            if (swapAmount == 0) {
                amountIn = ethIn ? msg.value : balanceOf(inputToken);
                if (amountIn == 0) revert BadSwap();
            } else {
                amountIn = swapAmount;
                if (ethIn && msg.value != amountIn) revert InvalidMsgVal();
            }
        }

        // ---- pre-fund router (Curve pools pull via transferFrom(router)) ----
        address firstToken = ethIn ? WETH : inputToken;

        {
            uint256 need = amountIn;
            if (!_useTransientBalance(address(this), firstToken, 0, need)) {
                if (ethIn) {
                    if (msg.value < need) revert InvalidMsgVal();
                    wrap(need); // wrap exactly what we need as WETH
                } else {
                    safeTransferFrom(firstToken, msg.sender, address(this), need);
                }
            }
        }

        // ---- execute the route (forward pass) ----
        address curIn = inputToken;
        amount = amountIn; // start with dx

        unchecked {
            for (uint256 i; i <= lastIdx; ++i) {
                address pool = route[i * 2 + 1];
                address nextToken = route[(i + 1) * 2];
                uint256[4] memory p = swapParams[i]; // [i, j, swap_type, pool_type]
                uint256 st = p[2];
                uint256 pt = p[3];

                if (st == 8) {
                    if (_isETH(curIn) && nextToken == WETH) {
                        // if first hop, we already wrapped in pre-fund; otherwise wrap what we just got:
                        if (i != 0) {
                            if (address(this).balance < amount) revert BadSwap();
                            wrap(amount);
                        }
                        curIn = WETH;
                    } else if (curIn == WETH && _isETH(nextToken)) {
                        unwrapETH(amount);
                        curIn = address(0); // normalize to 0x00 internally
                    } else {
                        revert BadSwap();
                    }
                    continue;
                }

                // ---- lazy approve current input token for this pool (ERC20 only) ----
                address inToken = _isETH(curIn) ? WETH : curIn;
                if (allowance(inToken, address(this), pool) == 0) {
                    safeApprove(inToken, pool, type(uint256).max);
                }

                // track output balance before hop
                uint256 outBalBefore =
                    _isETH(nextToken) ? address(this).balance : balanceOf(nextToken);

                // perform hop:
                if (st == 1) {
                    if (pt == 10) {
                        IStableNgPool(pool)
                            .exchange(int128(int256(p[0])), int128(int256(p[1])), amount, 0);
                    } else {
                        ICryptoNgPool(pool).exchange(p[0], p[1], amount, 0);
                    }
                } else if (st == 2) {
                    IStableNgMetaPool(pool)
                        .exchange_underlying(int128(int256(p[0])), int128(int256(p[1])), amount, 0);
                } else if (st == 4) {
                    if (pt == 10) {
                        uint256[8] memory a;
                        a[p[0]] = amount;
                        IStableNgPool(pool).add_liquidity(a, 0);
                    } else if (pt == 20) {
                        uint256[2] memory a2;
                        a2[p[0]] = amount;
                        ITwoCryptoNgPool(pool).add_liquidity(a2, 0);
                    } else if (pt == 30) {
                        uint256[3] memory a3;
                        a3[p[0]] = amount;
                        ITriCryptoNgPool(pool).add_liquidity(a3, 0);
                    } else {
                        revert BadSwap();
                    }
                } else if (st == 6) {
                    if (pt == 10) {
                        IStableNgPool(pool)
                            .remove_liquidity_one_coin(amount, int128(int256(p[1])), 0);
                    } else {
                        ICryptoNgPool(pool).remove_liquidity_one_coin(amount, p[1], 0);
                    }
                } else {
                    revert BadSwap();
                }

                // compute output of hop:
                uint256 outBalAfter =
                    _isETH(nextToken) ? address(this).balance : balanceOf(nextToken);
                if (outBalAfter <= outBalBefore) revert BadSwap();
                amount = outBalAfter - outBalBefore; // next hop input
                curIn = nextToken;
            }
        }

        // ---- finalize & slippage ----
        if (!exactOut) {
            amountOut = amount;
            if (amountLimit != 0 && amountOut < amountLimit) revert Slippage();
        } else {
            // actual produced amount is `amount`; must be >= desired swapAmount:
            if (amount < swapAmount) revert Slippage();
            amountOut = swapAmount; // user-facing target
        }

        // ---- deliver final output to `to` and refund surplus output (exactOut) ----
        if (!exactOut) {
            // deliver full amount for exact-in:
            if (_isETH(outputToken)) {
                _safeTransferETH(to, amount);
            } else if (to == address(this)) {
                depositFor(outputToken, 0, amount, to); // chaining
            } else {
                safeTransfer(outputToken, to, amount);
            }
        } else {
            // send only swapAmount to `to`; refund surplus to msg.sender:
            uint256 surplus = amount - swapAmount;
            if (_isETH(outputToken)) {
                // pay receiver
                _safeTransferETH(to, swapAmount);
                // refund any extra output
                if (surplus != 0) _safeTransferETH(msg.sender, surplus);
            } else {
                if (to == address(this)) {
                    // chaining: only mark the requested target amount
                    depositFor(outputToken, 0, swapAmount, to);
                } else {
                    safeTransfer(outputToken, to, swapAmount);
                }
                if (surplus != 0) safeTransfer(outputToken, msg.sender, surplus);
            }
        }

        // ---- leftover input refund (exactOut only, not chaining) ----
        if (exactOut && to != address(this)) {
            if (ethIn) {
                // refund any ETH dust first:
                uint256 e = address(this).balance;
                if (e != 0) _safeTransferETH(msg.sender, e);

                // refund any *WETH* dust created by positive slippage:
                uint256 w = balanceOf(WETH);
                if (w != 0) {
                    unwrapETH(w);
                    _safeTransferETH(msg.sender, w);
                }
            } else {
                // non-ETH inputs already use `firstToken`:
                uint256 refund = balanceOf(firstToken);
                if (refund != 0) safeTransfer(firstToken, msg.sender, refund);
            }
        }
    }

    function _isETH(address a) internal pure returns (bool r) {
        assembly { r := or(iszero(a), eq(a, CURVE_ETH)) }
    }

    /// @dev To be called for zAMM following deposit() or other swaps in sequence.
    function addLiquidity(
        PoolKey calldata poolKey,
        uint256 amount0Desired,
        uint256 amount1Desired,
        uint256 amount0Min,
        uint256 amount1Min,
        address to,
        uint256 deadline
    ) public payable returns (uint256 amount0, uint256 amount1, uint256 liquidity) {
        bool ethIn = (poolKey.token0 == address(0));
        (amount0, amount1, liquidity) = IZAMM(ZAMM).addLiquidity{value: ethIn ? amount0Desired : 0}(
            poolKey, amount0Desired, amount1Desired, amount0Min, amount1Min, to, deadline
        );
    }

    function ensureAllowance(address token, bool is6909, address to) public payable onlyOwner {
        if (is6909) IERC6909(token).setOperator(to, true);
        else safeApprove(token, to, type(uint256).max);
    }

    // ** PERMIT HELPERS

    function permit(address token, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
        public
        payable
    {
        IERC2612(token).permit(msg.sender, address(this), value, deadline, v, r, s);
    }

    function permitDAI(uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s)
        public
        payable
    {
        IDAIPermit(DAI).permit(msg.sender, address(this), nonce, expiry, true, v, r, s);
    }

    function permit2TransferFrom(
        address token,
        uint256 amount,
        uint256 nonce,
        uint256 deadline,
        bytes calldata signature
    ) public payable {
        IPermit2(PERMIT2)
            .permitTransferFrom(
                IPermit2.PermitTransferFrom({
                    permitted: IPermit2.TokenPermissions({token: token, amount: amount}),
                    nonce: nonce,
                    deadline: deadline
                }),
                IPermit2.SignatureTransferDetails({to: address(this), requestedAmount: amount}),
                msg.sender,
                signature
            );
        depositFor(token, 0, amount, address(this));
    }

    function permit2BatchTransferFrom(
        IPermit2.TokenPermissions[] calldata permitted,
        uint256 nonce,
        uint256 deadline,
        bytes calldata signature
    ) public payable {
        uint256 len = permitted.length;
        IPermit2.SignatureTransferDetails[] memory details =
            new IPermit2.SignatureTransferDetails[](len);

        for (uint256 i; i != len; ++i) {
            details[i] = IPermit2.SignatureTransferDetails({
                to: address(this), requestedAmount: permitted[i].amount
            });
        }

        IPermit2(PERMIT2)
            .permitBatchTransferFrom(
                IPermit2.PermitBatchTransferFrom({
                    permitted: permitted, nonce: nonce, deadline: deadline
                }),
                details,
                msg.sender,
                signature
            );

        for (uint256 i; i != len; ++i) {
            depositFor(permitted[i].token, 0, permitted[i].amount, address(this));
        }
    }

    // ** MULTISWAP HELPER

    function multicall(bytes[] calldata data) public payable returns (bytes[] memory results) {
        results = new bytes[](data.length);
        for (uint256 i; i != data.length; ++i) {
            (bool ok, bytes memory result) = address(this).delegatecall(data[i]);
            if (!ok) {
                assembly ("memory-safe") {
                    revert(add(result, 0x20), mload(result))
                }
            }
            results[i] = result;
        }
    }

    // ** TRANSIENT STORAGE

    function deposit(address token, uint256 id, uint256 amount) public payable {
        if (msg.value != 0) {
            require(id == 0, InvalidId());
            if (token == WETH) {
                require(msg.value == amount, InvalidMsgVal());
                _safeTransferETH(WETH, amount); // wrap to WETH
            } else {
                require(msg.value == (token == address(0) ? amount : 0), InvalidMsgVal());
            }
        }
        if (token != address(0) && msg.value == 0) {
            if (id == 0) safeTransferFrom(token, msg.sender, address(this), amount);
            else IERC6909(token).transferFrom(msg.sender, address(this), id, amount);
        }
        depositFor(token, id, amount, address(this)); // transient storage tracker
    }

    function _useTransientBalance(address user, address token, uint256 id, uint256 amount)
        internal
        returns (bool credited)
    {
        assembly ("memory-safe") {
            let m := mload(0x40)
            mstore(0x00, user)
            mstore(0x20, token)
            mstore(0x40, id)
            let slot := keccak256(0x00, 0x60)
            let bal := tload(slot)
            if iszero(lt(bal, amount)) {
                tstore(slot, sub(bal, amount))
                credited := 1
            }
            mstore(0x40, m)
        }
    }

    function _safeTransferETH(address to, uint256 amount) internal {
        if (to == address(this)) {
            depositFor(address(0), 0, amount, to);
            return;
        }
        assembly ("memory-safe") {
            if iszero(call(gas(), to, amount, codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, 0xb12d13eb)
                revert(0x1c, 0x04)
            }
        }
    }

    // ** RECEIVER & SWEEPER

    receive() external payable {}

    function sweep(address token, uint256 id, uint256 amount, address to) public payable {
        if (token == address(0)) {
            _safeTransferETH(to, amount == 0 ? address(this).balance : amount);
        } else if (id == 0) {
            safeTransfer(token, to, amount == 0 ? balanceOf(token) : amount);
        } else {
            IERC6909(token)
                .transfer(
                    to, id, amount == 0 ? IERC6909(token).balanceOf(address(this), id) : amount
                );
        }
    }

    // ** WETH HELPERS

    function wrap(uint256 amount) public payable {
        amount = amount == 0 ? address(this).balance : amount;
        _safeTransferETH(WETH, amount);
        depositFor(WETH, 0, amount, address(this));
    }

    function unwrap(uint256 amount) public payable {
        unwrapETH(amount == 0 ? balanceOf(WETH) : amount);
    }

    // ** POOL HELPERS

    function _v2PoolFor(address tokenA, address tokenB, bool sushi)
        internal
        pure
        returns (address v2pool, bool zeroForOne)
    {
        unchecked {
            (address token0, address token1, bool zF1) = _sortTokens(tokenA, tokenB);
            zeroForOne = zF1;
            v2pool = address(
                uint160(
                    uint256(
                        keccak256(
                            abi.encodePacked(
                                hex"ff",
                                !sushi ? V2_FACTORY : SUSHI_FACTORY,
                                keccak256(abi.encodePacked(token0, token1)),
                                !sushi ? V2_POOL_INIT_CODE_HASH : SUSHI_POOL_INIT_CODE_HASH
                            )
                        )
                    )
                )
            );
        }
    }

    function _v3PoolFor(address tokenA, address tokenB, uint24 fee)
        internal
        pure
        returns (address v3pool, bool zeroForOne)
    {
        (address token0, address token1, bool zF1) = _sortTokens(tokenA, tokenB);
        zeroForOne = zF1;
        v3pool = _computeV3pool(token0, token1, fee);
    }

    function _computeV3pool(address token0, address token1, uint24 fee)
        internal
        pure
        returns (address v3pool)
    {
        bytes32 salt = _hash(token0, token1, fee);
        assembly ("memory-safe") {
            mstore8(0x00, 0xff)
            mstore(0x35, V3_POOL_INIT_CODE_HASH)
            mstore(0x01, shl(96, V3_FACTORY))
            mstore(0x15, salt)
            v3pool := keccak256(0x00, 0x55)
            mstore(0x35, 0)
        }
    }

    function _hash(address value0, address value1, uint24 value2)
        internal
        pure
        returns (bytes32 result)
    {
        assembly ("memory-safe") {
            let m := mload(0x40)
            mstore(m, value0)
            mstore(add(m, 0x20), value1)
            mstore(add(m, 0x40), value2)
            result := keccak256(m, 0x60)
        }
    }

    function _sortTokens(address tokenA, address tokenB)
        internal
        pure
        returns (address token0, address token1, bool zeroForOne)
    {
        (token0, token1) = (zeroForOne = tokenA < tokenB) ? (tokenA, tokenB) : (tokenB, tokenA);
    }

    // EXECUTE EXTENSIONS

    address _owner;

    modifier onlyOwner() {
        require(msg.sender == _owner, Unauthorized());
        _;
    }

    mapping(address target => bool) _isTrustedForCall;

    function trust(address target, bool ok) public payable onlyOwner {
        _isTrustedForCall[target] = ok;
    }

    function transferOwnership(address owner) public payable onlyOwner {
        emit OwnershipTransferred(msg.sender, _owner = owner);
    }

    function execute(address target, uint256 value, bytes calldata data)
        public
        payable
        returns (bytes memory result)
    {
        require(_isTrustedForCall[target], Unauthorized());
        assembly ("memory-safe") {
            tstore(0x00, 1) // lock callback (V3/V4)
            result := mload(0x40)
            calldatacopy(result, data.offset, data.length)
            if iszero(call(gas(), target, value, result, data.length, codesize(), 0x00)) {
                returndatacopy(result, 0x00, returndatasize())
                revert(result, returndatasize())
            }
            mstore(result, returndatasize())
            let o := add(result, 0x20)
            returndatacopy(o, 0x00, returndatasize())
            mstore(0x40, add(o, returndatasize()))
            tstore(0x00, 0) // unlock callback
        }
    }

    // SNWAP - GENERIC EXECUTOR ****

    function snwap(
        address tokenIn,
        uint256 amountIn,
        address recipient,
        address tokenOut,
        uint256 amountOutMin,
        address executor,
        bytes calldata executorData
    ) public payable returns (uint256 amountOut) {
        uint256 initialBalance = tokenOut == address(0)
            ? recipient.balance
            : balanceOfAccount(tokenOut, recipient);

        if (tokenIn != address(0)) {
            if (amountIn != 0) {
                safeTransferFrom(tokenIn, msg.sender, executor, amountIn);
            } else {
                unchecked {
                    uint256 bal = balanceOf(tokenIn);
                    if (bal > 1) safeTransfer(tokenIn, executor, bal - 1);
                }
            }
        }

        safeExecutor.execute{value: msg.value}(executor, executorData);

        uint256 finalBalance =
            tokenOut == address(0) ? recipient.balance : balanceOfAccount(tokenOut, recipient);
        amountOut = finalBalance - initialBalance;
        if (amountOut < amountOutMin) revert SnwapSlippage(tokenOut, amountOut, amountOutMin);
        if (recipient == address(this)) depositFor(tokenOut, 0, amountOut, address(this));
    }

    function snwapMulti(
        address tokenIn,
        uint256 amountIn,
        address recipient,
        address[] calldata tokensOut,
        uint256[] calldata amountsOutMin,
        address executor,
        bytes calldata executorData
    ) public payable returns (uint256[] memory amountsOut) {
        uint256 len = tokensOut.length;
        uint256[] memory initBals = new uint256[](len);
        for (uint256 i; i != len; ++i) {
            initBals[i] = tokensOut[i] == address(0)
                ? recipient.balance
                : balanceOfAccount(tokensOut[i], recipient);
        }

        if (tokenIn != address(0)) {
            if (amountIn != 0) {
                safeTransferFrom(tokenIn, msg.sender, executor, amountIn);
            } else {
                unchecked {
                    uint256 bal = balanceOf(tokenIn);
                    if (bal > 1) safeTransfer(tokenIn, executor, bal - 1);
                }
            }
        }

        safeExecutor.execute{value: msg.value}(executor, executorData);

        amountsOut = new uint256[](len);
        for (uint256 i; i != len; ++i) {
            uint256 finalBal = tokensOut[i] == address(0)
                ? recipient.balance
                : balanceOfAccount(tokensOut[i], recipient);
            amountsOut[i] = finalBal - initBals[i];
            if (amountsOut[i] < amountsOutMin[i]) {
                revert SnwapSlippage(tokensOut[i], amountsOut[i], amountsOutMin[i]);
            }
            if (recipient == address(this)) {
                depositFor(tokensOut[i], 0, amountsOut[i], address(this));
            }
        }
    }

    // LIDO STAKING ****

    // **** EXACT ETH IN - MAX TOKEN OUT
    // note: If user doesn't care about `to` then just send ETH to STETH or WSTETH

    function exactETHToSTETH(address to) public payable returns (uint256 shares) {
        assembly ("memory-safe") {
            // submit(address referral) -> returns shares
            mstore(0x00, 0xa1903eab000000000000000000000000)
            if iszero(call(gas(), STETH, callvalue(), 0x10, 0x24, 0x00, 0x20)) {
                revert(0x00, 0x00)
            }
            shares := mload(0x00)
            // transferShares(address to, uint256 shares)
            mstore(0x00, 0x8fcb4e5b000000000000000000000000)
            mstore(0x14, to)
            mstore(0x34, shares)
            if iszero(call(gas(), STETH, 0, 0x10, 0x44, codesize(), 0x00)) {
                revert(0x00, 0x00)
            }
            mstore(0x34, 0)
        }
    }

    function exactETHToWSTETH(address to) public payable returns (uint256 wstOut) {
        assembly ("memory-safe") {
            // Send ETH to WSTETH (triggers receive() which auto-wraps)
            if iszero(call(gas(), WSTETH, callvalue(), codesize(), 0x00, codesize(), 0x00)) {
                revert(0x00, 0x00)
            }
            // balanceOf(address) to get wstETH received
            mstore(0x14, address())
            mstore(0x00, 0x70a08231000000000000000000000000)
            if iszero(staticcall(gas(), WSTETH, 0x10, 0x24, 0x00, 0x20)) {
                revert(0x00, 0x00)
            }
            wstOut := mload(0x00)
            // transfer(address to, uint256 amount)
            mstore(0x00, 0xa9059cbb000000000000000000000000)
            mstore(0x14, to)
            mstore(0x34, wstOut)
            if iszero(call(gas(), WSTETH, 0, 0x10, 0x44, codesize(), 0x00)) {
                revert(0x00, 0x00)
            }
            mstore(0x34, 0)
        }
    }

    // **** EXACT TOKEN OUT - REFUND EXCESS ETH IN

    function ethToExactSTETH(address to, uint256 exactOut) public payable {
        assembly ("memory-safe") {
            // getSharesByPooledEth(1e18) to get share rate
            mstore(0x00, 0xd5002f2e000000000000000000000000)
            if iszero(staticcall(gas(), STETH, 0x10, 0x04, 0x00, 0x20)) {
                revert(0x00, 0x00)
            }
            let S := mload(0x00)
            // getTotalPooledEther()
            mstore(0x00, 0x37cfdaca000000000000000000000000)
            if iszero(staticcall(gas(), STETH, 0x10, 0x04, 0x00, 0x20)) {
                revert(0x00, 0x00)
            }
            let T := mload(0x00)
            let z := mul(exactOut, S)
            let sharesNeeded := add(iszero(iszero(mod(z, T))), div(z, T))
            z := mul(sharesNeeded, T)
            let ethIn := add(iszero(iszero(mod(z, S))), div(z, S))
            if gt(ethIn, callvalue()) { revert(0x00, 0x00) }
            // submit() to stake ETH
            if iszero(call(gas(), STETH, ethIn, codesize(), 0x00, codesize(), 0x00)) {
                revert(0x00, 0x00)
            }
            // transferShares(address to, uint256 shares)
            mstore(0x00, 0x8fcb4e5b000000000000000000000000)
            mstore(0x14, to)
            mstore(0x34, sharesNeeded)
            if iszero(call(gas(), STETH, 0, 0x10, 0x44, codesize(), 0x00)) {
                revert(0x00, 0x00)
            }
            mstore(0x34, 0)
            // Refund excess ETH
            if gt(callvalue(), ethIn) {
                if iszero(
                    call(
                        gas(),
                        caller(),
                        sub(callvalue(), ethIn),
                        codesize(),
                        0x00,
                        codesize(),
                        0x00
                    )
                ) {
                    // ETHTransferFailed selector: 0xb12d13eb
                    mstore(0x00, 0xb12d13eb)
                    revert(0x1c, 0x04)
                }
            }
        }
    }

    function ethToExactWSTETH(address to, uint256 exactOut) public payable {
        assembly ("memory-safe") {
            // getSharesByPooledEth(1e18) to get share rate
            mstore(0x00, 0xd5002f2e000000000000000000000000)
            if iszero(staticcall(gas(), STETH, 0x10, 0x04, 0x00, 0x20)) {
                revert(0x00, 0x00)
            }
            let S := mload(0x00)
            // getTotalPooledEther()
            mstore(0x00, 0x37cfdaca000000000000000000000000)
            if iszero(staticcall(gas(), STETH, 0x10, 0x04, 0x00, 0x20)) {
                revert(0x00, 0x00)
            }
            let ethIn := mul(exactOut, mload(0x00))
            ethIn := add(iszero(iszero(mod(ethIn, S))), div(ethIn, S))
            if gt(ethIn, callvalue()) { revert(0x00, 0x00) }
            // Send ETH to WSTETH (triggers receive() which auto-wraps)
            if iszero(call(gas(), WSTETH, ethIn, codesize(), 0x00, codesize(), 0x00)) {
                revert(0x00, 0x00)
            }
            // transfer(address to, uint256 amount)
            mstore(0x00, 0xa9059cbb000000000000000000000000)
            mstore(0x14, to)
            mstore(0x34, exactOut)
            if iszero(call(gas(), WSTETH, 0, 0x10, 0x44, codesize(), 0x00)) {
                revert(0x00, 0x00)
            }
            mstore(0x34, 0)
            // Refund excess ETH
            if gt(callvalue(), ethIn) {
                if iszero(
                    call(
                        gas(),
                        caller(),
                        sub(callvalue(), ethIn),
                        codesize(),
                        0x00,
                        codesize(),
                        0x00
                    )
                ) {
                    // ETHTransferFailed selector: 0xb12d13eb
                    mstore(0x00, 0xb12d13eb)
                    revert(0x1c, 0x04)
                }
            }
        }
    }

    // NameNFT - REVEAL NAME ****

    function onERC721Received(address, address, uint256, bytes calldata)
        public
        pure
        returns (bytes4)
    {
        return this.onERC721Received.selector;
    }

    /// @notice Reveal and register a .wei name after commitment.
    /// @dev User must first commit on NameNFT using `makeCommitment(label, routerAddress, derivedSecret)`.
    ///      The derived secret is `keccak256(abi.encode(innerSecret, to))`, binding the commitment
    ///      to the intended recipient. This prevents mempool front-running of the reveal tx.
    ///      Chain with swap via multicall for atomic swap-to-reveal. Excess ETH stays in
    ///      router for sweep.
    function revealName(string calldata label, bytes32 innerSecret, address to)
        public
        payable
        returns (uint256 tokenId)
    {
        bytes32 secret = keccak256(abi.encode(innerSecret, to));
        uint256 val = address(this).balance;
        _useTransientBalance(address(this), address(0), 0, val);
        tokenId = INameNFT(NAME_NFT).reveal{value: val}(label, secret);
        INameNFT(NAME_NFT).transferFrom(address(this), to, tokenId);
    }
}

// NameNFT helpers:

address constant NAME_NFT = 0x0000000000696760E15f265e828DB644A0c242EB;

interface INameNFT {
    function reveal(string calldata label, bytes32 secret)
        external
        payable
        returns (uint256 tokenId);
    function transferFrom(address from, address to, uint256 tokenId) external;
}

// Lido helpers:

address constant STETH = 0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84;
address constant WSTETH = 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0;

// Uniswap helpers:

address constant V2_FACTORY = 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f;
bytes32 constant V2_POOL_INIT_CODE_HASH =
    0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f;

// ** SushiSwap:

address constant SUSHI_FACTORY = 0xC0AEe478e3658e2610c5F7A4A2E1777cE9e4f2Ac;
bytes32 constant SUSHI_POOL_INIT_CODE_HASH =
    0xe18a34eb0e04b04f7a0ac29a6e80748dca96319b42c54d679cb821dca90c6303;

interface IV2Pool {
    function swap(uint256 amount0Out, uint256 amount1Out, address to, bytes calldata data) external;
    function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32);
}

address constant V3_FACTORY = 0x1F98431c8aD98523631AE4a59f267346ea31F984;
bytes32 constant V3_POOL_INIT_CODE_HASH =
    0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54;
uint160 constant MIN_SQRT_RATIO_PLUS_ONE = 4295128740;
uint160 constant MAX_SQRT_RATIO_MINUS_ONE = 1461446703485210103287273052203988822378723970341;

interface IV3Pool {
    function swap(
        address recipient,
        bool zeroForOne,
        int256 amountSpecified,
        uint160 sqrtPriceLimitX96,
        bytes calldata data
    ) external returns (int256 amount0, int256 amount1);
}

address constant V4_POOL_MANAGER = 0x000000000004444c5dc75cB358380D2e3dE08A90;

struct V4PoolKey {
    address currency0;
    address currency1;
    uint24 fee;
    int24 tickSpacing;
    address hooks;
}

struct V4SwapParams {
    bool zeroForOne;
    int256 amountSpecified;
    uint160 sqrtPriceLimitX96;
}

interface IV4PoolManager {
    function unlock(bytes calldata data) external returns (bytes memory);
    function swap(V4PoolKey memory key, V4SwapParams memory params, bytes calldata hookData)
        external
        returns (int256 swapDelta);
    function sync(address currency) external;
    function settle() external payable returns (uint256 paid);
    function take(address currency, address to, uint256 amount) external;
}

using BalanceDeltaLibrary for int256;

library BalanceDeltaLibrary {
    function amount0(int256 balanceDelta) internal pure returns (int128 _amount0) {
        assembly ("memory-safe") {
            _amount0 := sar(128, balanceDelta)
        }
    }

    function amount1(int256 balanceDelta) internal pure returns (int128 _amount1) {
        assembly ("memory-safe") {
            _amount1 := signextend(15, balanceDelta)
        }
    }
}

// zAMM helpers:

address constant ZAMM = 0x000000000000040470635EB91b7CE4D132D616eD;
address constant ZAMM_0 = 0x00000000000008882D72EfA6cCE4B6a40b24C860;

struct PoolKey {
    uint256 id0;
    uint256 id1;
    address token0;
    address token1;
    uint256 feeOrHook;
}

interface IZAMM {
    function addLiquidity(
        PoolKey calldata poolKey,
        uint256 amount0Desired,
        uint256 amount1Desired,
        uint256 amount0Min,
        uint256 amount1Min,
        address to,
        uint256 deadline
    ) external payable returns (uint256 amount0, uint256 amount1, uint256 liquidity);
}

// Curve helpers:

address constant CURVE_ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;

interface IStableNgPool {
    function get_dx(int128 i, int128 j, uint256 out_amount) external view returns (uint256);
    function exchange(int128 i, int128 j, uint256 dx, uint256 min_dy) external;
    function calc_token_amount(uint256[8] calldata _amounts, bool _is_deposit)
        external
        view
        returns (uint256);
    function add_liquidity(uint256[8] calldata _amounts, uint256 _min_mint_amount)
        external
        returns (uint256);
    function calc_withdraw_one_coin(uint256 token_amount, int128 i) external view returns (uint256);
    function remove_liquidity_one_coin(uint256 token_amount, int128 i, uint256 min_amount) external;
}

interface IStableNgMetaPool {
    function get_dx_underlying(int128 i, int128 j, uint256 amount) external view returns (uint256);
    function exchange_underlying(int128 i, int128 j, uint256 dx, uint256 min_dy) external;
}

interface ICryptoNgPool {
    function get_dx(uint256 i, uint256 j, uint256 out_amount) external view returns (uint256);
    function exchange(uint256 i, uint256 j, uint256 dx, uint256 min_dy) external;
    function calc_withdraw_one_coin(uint256 token_amount, uint256 i) external view returns (uint256);
    function remove_liquidity_one_coin(uint256 token_amount, uint256 i, uint256 min_amount) external;
}

interface ITwoCryptoNgPool {
    function calc_token_amount(uint256[2] calldata amounts, bool is_deposit)
        external
        view
        returns (uint256);
    function add_liquidity(uint256[2] calldata amounts, uint256 min_mint_amount)
        external
        returns (uint256);
}

interface ITriCryptoNgPool {
    function calc_token_amount(uint256[3] calldata amounts, bool is_deposit)
        external
        view
        returns (uint256);
    function add_liquidity(uint256[3] calldata amounts, uint256 min_mint_amount)
        external
        returns (uint256);
}

// Solady safe transfer helpers:

error TransferFailed();

function safeTransfer(address token, address to, uint256 amount) {
    assembly ("memory-safe") {
        mstore(0x14, to)
        mstore(0x34, amount)
        mstore(0x00, 0xa9059cbb000000000000000000000000)
        let success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
        if iszero(and(eq(mload(0x00), 1), success)) {
            if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
                mstore(0x00, 0x90b8ec18)
                revert(0x1c, 0x04)
            }
        }
        mstore(0x34, 0)
    }
}

error TransferFromFailed();

function safeTransferFrom(address token, address from, address to, uint256 amount) {
    assembly ("memory-safe") {
        let m := mload(0x40)
        mstore(0x60, amount)
        mstore(0x40, to)
        mstore(0x2c, shl(96, from))
        mstore(0x0c, 0x23b872dd000000000000000000000000)
        let success := call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
        if iszero(and(eq(mload(0x00), 1), success)) {
            if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
                mstore(0x00, 0x7939f424)
                revert(0x1c, 0x04)
            }
        }
        mstore(0x60, 0)
        mstore(0x40, m)
    }
}

error ApproveFailed();

function safeApprove(address token, address to, uint256 amount) {
    assembly ("memory-safe") {
        mstore(0x14, to)
        mstore(0x34, amount)
        mstore(0x00, 0x095ea7b3000000000000000000000000)
        let success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
        if iszero(and(eq(mload(0x00), 1), success)) {
            if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
                mstore(0x00, 0x3e3f8f73)
                revert(0x1c, 0x04)
            }
        }
        mstore(0x34, 0)
    }
}

function balanceOf(address token) view returns (uint256 amount) {
    assembly ("memory-safe") {
        mstore(0x14, address())
        mstore(0x00, 0x70a08231000000000000000000000000)
        amount := mul(
            mload(0x20),
            and(gt(returndatasize(), 0x1f), staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20))
        )
    }
}

function allowance(address token, address owner, address spender) view returns (uint256 amount) {
    assembly ("memory-safe") {
        let m := mload(0x40)
        mstore(0x40, spender)
        mstore(0x2c, shl(96, owner))
        mstore(0x0c, 0xdd62ed3e000000000000000000000000)
        amount := mul(
            mload(0x20),
            and(gt(returndatasize(), 0x1f), staticcall(gas(), token, 0x1c, 0x44, 0x20, 0x20))
        )
        mstore(0x40, m)
    }
}

function balanceOfAccount(address token, address account) view returns (uint256 amount) {
    assembly ("memory-safe") {
        mstore(0x14, account)
        mstore(0x00, 0x70a08231000000000000000000000000)
        amount := mul(
            mload(0x20),
            and(gt(returndatasize(), 0x1f), staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20))
        )
    }
}

// ** ERC6909

interface IERC6909 {
    function setOperator(address spender, bool approved) external returns (bool);
    function balanceOf(address owner, uint256 id) external view returns (uint256 amount);
    function transfer(address receiver, uint256 id, uint256 amount) external returns (bool);
    function transferFrom(address sender, address receiver, uint256 id, uint256 amount)
        external
        returns (bool);
}

// Low-level WETH helpers - we know WETH so we can make assumptions:

address constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;

function wrapETH(address pool, uint256 amount) {
    assembly ("memory-safe") {
        pop(call(gas(), WETH, amount, codesize(), 0x00, codesize(), 0x00))
        mstore(0x14, pool)
        mstore(0x34, amount)
        mstore(0x00, 0xa9059cbb000000000000000000000000)
        pop(call(gas(), WETH, 0, 0x10, 0x44, codesize(), 0x00))
        mstore(0x34, 0)
    }
}

function unwrapETH(uint256 amount) {
    assembly ("memory-safe") {
        mstore(0x00, 0x2e1a7d4d)
        mstore(0x20, amount)
        pop(call(gas(), WETH, 0, 0x1c, 0x24, codesize(), 0x00))
    }
}

// ** TRANSIENT DEPOSIT

function depositFor(address token, uint256 id, uint256 amount, address _for) {
    assembly ("memory-safe") {
        let m := mload(0x40)
        mstore(0x00, _for)
        mstore(0x20, token)
        mstore(0x40, id)
        let slot := keccak256(0x00, 0x60)
        tstore(slot, add(tload(slot), amount))
        mstore(0x40, m)
    }
}

// ** PERMIT HELPERS

address constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
address constant PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3;

interface IERC2612 {
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;
}

interface IDAIPermit {
    function permit(
        address holder,
        address spender,
        uint256 nonce,
        uint256 expiry,
        bool allowed,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;
}

interface IPermit2 {
    struct TokenPermissions {
        address token;
        uint256 amount;
    }

    struct PermitTransferFrom {
        TokenPermissions permitted;
        uint256 nonce;
        uint256 deadline;
    }

    struct PermitBatchTransferFrom {
        TokenPermissions[] permitted;
        uint256 nonce;
        uint256 deadline;
    }

    struct SignatureTransferDetails {
        address to;
        uint256 requestedAmount;
    }

    function permitTransferFrom(
        PermitTransferFrom calldata permit,
        SignatureTransferDetails calldata transferDetails,
        address owner,
        bytes calldata signature
    ) external;

    function permitBatchTransferFrom(
        PermitBatchTransferFrom calldata permit,
        SignatureTransferDetails[] calldata transferDetails,
        address owner,
        bytes calldata signature
    ) external;
}

// ** SNWAP HELPERS

// modified from 0xAC4c6e212A361c968F1725b4d055b47E63F80b75 - sushi yum

/// @dev SafeExecutor - has no token approvals, safe for arbitrary external calls
contract SafeExecutor {
    function execute(address target, bytes calldata data) public payable {
        assembly ("memory-safe") {
            let m := mload(0x40)
            calldatacopy(m, data.offset, data.length)
            if iszero(call(gas(), target, callvalue(), m, data.length, codesize(), 0x00)) {
                returndatacopy(m, 0x00, returndatasize())
                revert(m, returndatasize())
            }
        }
    }
}

Settings
{
  "remappings": [
    "@solady/=lib/solady/",
    "@soledge/=lib/soledge/",
    "@forge/=lib/forge-std/src/",
    "solady/=lib/solady/src/",
    "soledge/=lib/soledge/src/",
    "forge-std/=lib/forge-std/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 9999999
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "prague",
  "viaIR": true
}

Contract Security Audit

Contract ABI

API
[{"inputs":[],"stateMutability":"payable","type":"constructor"},{"inputs":[],"name":"BadSwap","type":"error"},{"inputs":[],"name":"ETHTransferFailed","type":"error"},{"inputs":[],"name":"Expired","type":"error"},{"inputs":[],"name":"InvalidId","type":"error"},{"inputs":[],"name":"InvalidMsgVal","type":"error"},{"inputs":[],"name":"Slippage","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"received","type":"uint256"},{"internalType":"uint256","name":"minimum","type":"uint256"}],"name":"SnwapSlippage","type":"error"},{"inputs":[],"name":"SwapExactInFail","type":"error"},{"inputs":[],"name":"SwapExactOutFail","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[{"components":[{"internalType":"uint256","name":"id0","type":"uint256"},{"internalType":"uint256","name":"id1","type":"uint256"},{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint256","name":"feeOrHook","type":"uint256"}],"internalType":"struct PoolKey","name":"poolKey","type":"tuple"},{"internalType":"uint256","name":"amount0Desired","type":"uint256"},{"internalType":"uint256","name":"amount1Desired","type":"uint256"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidity","outputs":[{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"bool","name":"is6909","type":"bool"},{"internalType":"address","name":"to","type":"address"}],"name":"ensureAllowance","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"exactOut","type":"uint256"}],"name":"ethToExactSTETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"exactOut","type":"uint256"}],"name":"ethToExactWSTETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"exactETHToSTETH","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"exactETHToWSTETH","outputs":[{"internalType":"uint256","name":"wstOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"execute","outputs":[{"internalType":"bytes","name":"result","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct IPermit2.TokenPermissions[]","name":"permitted","type":"tuple[]"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"permit2BatchTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"permit2TransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permitDAI","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"string","name":"label","type":"string"},{"internalType":"bytes32","name":"innerSecret","type":"bytes32"},{"internalType":"address","name":"to","type":"address"}],"name":"revealName","outputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"safeExecutor","outputs":[{"internalType":"contract SafeExecutor","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address","name":"executor","type":"address"},{"internalType":"bytes","name":"executorData","type":"bytes"}],"name":"snwap","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"address[]","name":"tokensOut","type":"address[]"},{"internalType":"uint256[]","name":"amountsOutMin","type":"uint256[]"},{"internalType":"address","name":"executor","type":"address"},{"internalType":"bytes","name":"executorData","type":"bytes"}],"name":"snwapMulti","outputs":[{"internalType":"uint256[]","name":"amountsOut","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"exactOut","type":"bool"},{"internalType":"address[11]","name":"route","type":"address[11]"},{"internalType":"uint256[4][5]","name":"swapParams","type":"uint256[4][5]"},{"internalType":"address[5]","name":"basePools","type":"address[5]"},{"internalType":"uint256","name":"swapAmount","type":"uint256"},{"internalType":"uint256","name":"amountLimit","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapCurve","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"exactOut","type":"bool"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"swapAmount","type":"uint256"},{"internalType":"uint256","name":"amountLimit","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapV2","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"exactOut","type":"bool"},{"internalType":"uint24","name":"swapFee","type":"uint24"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"swapAmount","type":"uint256"},{"internalType":"uint256","name":"amountLimit","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapV3","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"exactOut","type":"bool"},{"internalType":"uint24","name":"swapFee","type":"uint24"},{"internalType":"int24","name":"tickSpace","type":"int24"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"swapAmount","type":"uint256"},{"internalType":"uint256","name":"amountLimit","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapV4","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"exactOut","type":"bool"},{"internalType":"uint256","name":"feeOrHook","type":"uint256"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"idIn","type":"uint256"},{"internalType":"uint256","name":"idOut","type":"uint256"},{"internalType":"uint256","name":"swapAmount","type":"uint256"},{"internalType":"uint256","name":"amountLimit","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapVZ","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"sweep","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bool","name":"ok","type":"bool"}],"name":"trust","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"callbackData","type":"bytes"}],"name":"unlockCallback","outputs":[{"internalType":"bytes","name":"result","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"unwrap","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"wrap","outputs":[],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60a060408190526101158082016001600160401b0381118382101761012e5782916160ba833903905ff0801561012357608052737f39c581f595b53c5cb19bd0b3f8da6c935e2ca06014525f196034526f095ea7b30000000000000000000000005f5260205f604460108273ae7ab96520de3a18e5e111b5eaab095312d7fe845af18060015f511416156100f1575b5f603481905280546001600160a01b031916329081178255604051917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a3615f77908161014382396080518181816104de01528181612f6301526133a20152f35b3d73ae7ab96520de3a18e5e111b5eaab095312d7fe843b15171015610116575f61008e565b633e3f8f735f526004601cfd5b6040513d5f823e3d90fd5b634e487b7160e01b5f52604160045260245ffdfe6080604052600436101561014d575b36156100b7575f5c61014957609a3560601c6024356004358015801590610140575b156101185761004a60d63560e81c60ae3560601c85615ec8565b939073ffffffffffffffffffffffffffffffffffffffff811633036100f05784156100e95782905b61007d828430615c9c565b156100c05761008b92615da8565b6085355f1a61009657005b6100b792156100b957505b5f036100ac81615d03565b60c23560601c615b7c565b005b90506100a1565b6084355f1a156100d9576100d49250615e2f565b61008b565b6100d49260863560601c90615bc7565b8390610072565b7f82b42900000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f7c7f7bb9000000000000000000000000000000000000000000000000000000005f5260045ffd5b50811515610030565b5f80fd5b5f5f3560e01c806306262f1b146153ac57806309d31579146151d25780630efe6a8b14614fdd57806312db224a14613caf578063150b7a0214613c2157806321c0dad21461398b578063230390f4146138ac5780632cb9f974146136c65780633f896275146132a657806341abb1ef146131d157806347c1ba3a146131195780635f3bd1c814612e8f5780636e0a4f98146128235780637984d8b1146124195780637ac2ff7b1461233657806391dd734614611cfe5780639d5b5af8146113dc578063ac9650d8146111c5578063afeae12b14610cb0578063b61d27f614610b92578063bd6b76d714610a60578063c391b38114610914578063c42957a81461073e578063cb019b841461054f578063de0e9a3e14610502578063e8382b0114610493578063ea598cb01461045a578063f2fde38b146103775763f978602c14610297575061000e565b60207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610374576102c9615458565b8138818034737f39c581f595b53c5cb19bd0b3f8da6c935e2ca05af11561037257306014526f70a08231000000000000000000000000825260208260246010737f39c581f595b53c5cb19bd0b3f8da6c935e2ca05afa15610372578151906fa9059cbb00000000000000000000000083526014528060345281386044601083737f39c581f595b53c5cb19bd0b3f8da6c935e2ca05af11561037257602091603452604051908152f35b505b80fd5b5060207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610374576103aa615458565b81549073ffffffffffffffffffffffffffffffffffffffff82163303610432579073ffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffff0000000000000000000000000000000000000000921691829116178255337f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b6004837f82b42900000000000000000000000000000000000000000000000000000000008152fd5b5060207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457610490600435615a9b565b80f35b503461037457807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b5060207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457600435806105465750610490610541615c2e565b615d03565b61049090615d03565b5060807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457610582615458565b60243590604435610591615507565b9173ffffffffffffffffffffffffffffffffffffffff8116806105c85750610490935050806105c257504790615b7c565b90615b7c565b9092919085856105ee5750610490945050806105e857506105e882615c6f565b91615da8565b92935091908061072e57506040517efdd58e00000000000000000000000000000000000000000000000000000000815230600482015260248101859052602081604481865afa9081156106e75782916106f2575b509360209392916106ac95935b604051968795869485937f095bcdb60000000000000000000000000000000000000000000000000000000085526004850160409194939273ffffffffffffffffffffffffffffffffffffffff606083019616825260208201520152565b03925af180156106e7576106bf575b5080f35b6106bb9060203d6020116106e0575b6106d8818361568f565b81019061570e565b503d6106ce565b6040513d84823e3d90fd5b93929150506020833d602011610726575b816107106020938361568f565b8101031261014957915190919084906020610642565b3d9150610703565b9360209392916106ac959361064f565b507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360161016081126103725760a0136103745760a4356101243573ffffffffffffffffffffffffffffffffffffffff81168091036109105760609073ffffffffffffffffffffffffffffffffffffffff6107b7615765565b1661090657610164835b60405194859384927fc42957a80000000000000000000000000000000000000000000000000000000084526004356004850152602435602485015273ffffffffffffffffffffffffffffffffffffffff6108196154e4565b16604485015273ffffffffffffffffffffffffffffffffffffffff61083c615507565b166064850152608435608485015260a484015260c43560c484015260e43560e484015261010435610104840152610124830152610144356101448301526d040470635eb91b7ce4d132d616ed5af180156106e75782918380926108c1575b50506108bd90604051938493846040919493926060820195825260208201520152565b0390f35b92509250506060823d6060116108fe575b816108df6060938361568f565b810103126103745750805160208201516040909201516108bd5f61089a565b3d91506108d2565b61016484936107c1565b8280fd5b5060407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103745780610948615458565b6024356fd5002f2e00000000000000000000000083526020836004601073ae7ab96520de3a18e5e111b5eaab095312d7fe845afa15610a5c5782516f37cfdaca00000000000000000000000084526020846004601073ae7ab96520de3a18e5e111b5eaab095312d7fe845afa15610a5a578351820290808204910615150191348311610a5a578338818086737f39c581f595b53c5cb19bd0b3f8da6c935e2ca05af115610a5a576fa9059cbb000000000000000000000000845260145260345281386044601083737f39c581f595b53c5cb19bd0b3f8da6c935e2ca05af115610a575781603452803411610a395750f35b818038923403335af115610a4a5780f35b63b12d13eb90526004601cfd5b50fd5b505b5050fd5b5060407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103745780610a94615458565b6fd5002f2e00000000000000000000000082526020826004601073ae7ab96520de3a18e5e111b5eaab095312d7fe845afa15610a575781516f37cfdaca00000000000000000000000083526020836004601073ae7ab96520de3a18e5e111b5eaab095312d7fe845afa15610a5c57825190806024350282808204910615150191820290808204910615150191348311610a5a57833881808673ae7ab96520de3a18e5e111b5eaab095312d7fe845af115610a5a576f8fcb4e5b00000000000000000000000084526014526034528138604460108373ae7ab96520de3a18e5e111b5eaab095312d7fe845af115610a575781603452803411610a395750f35b5060607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457610bc5615458565b60443567ffffffffffffffff811161091057610be590369060040161555a565b73ffffffffffffffffffffffffffffffffffffffff839293168452600160205260ff60408520541615610c88579083916001835d80604051948537833892602435905af115610c7f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0903d81523d83602083013e610c7a3d820191602083019485604052805d6020855260408301906155cb565b030190f35b903d90823e3d90fd5b6004847f82b42900000000000000000000000000000000000000000000000000000000008152fd5b506101007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457610ce4615458565b610cec61554b565b90610cf5615588565b90610cfe615507565b91610d0761549e565b60e435421161119d5794849560a435819373ffffffffffffffffffffffffffffffffffffffff87931615928373ffffffffffffffffffffffffffffffffffffffff891615611181575b611165575b808786610d64858a8096615ec8565b9d8e9591948615611148578d8a6401000276a49a5b84158061113e575b6110c8575b81156110c15730945b156110565786039a7fffffff000000000000000000000000000000000000000000000000000000000060409b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000073ffffffffffffffffffffffffffffffffffffffff9a818c9a81610ea69a8d995b60408b90519c161560f81b60208d015260f81b60218c01523360601b60228c015260601b1660368a015260601b16604a88015260601b16605e86015260e81b16607284015260558352610e5160758461568f565b8a519b8c9a8b998a977f128acb0800000000000000000000000000000000000000000000000000000000895216600488015215156024870152604486015216606484015260a0608484015260a48301906155cb565b0393165af196871561104b5783918498611010575b5060c435610fa2575b5060409715610f865773ffffffffffffffffffffffffffffffffffffffff905b838112610f7e57965b838113610f78578303955b1615610f33575b15610f14575b50505082519182526020820152f35b60609186519382526020528086522082815c01905d83525f8080610f05565b4780151580610f58575b610f48575b50610eff565b610f529033615b7c565b5f610f42565b503073ffffffffffffffffffffffffffffffffffffffff86161415610f3d565b95610ef8565b830396610eed565b9573ffffffffffffffffffffffffffffffffffffffff90610ee4565b15610fef578715610fe957805b60c43510610fc1576040975b97610ec4565b6004837f7dd37f70000000000000000000000000000000000000000000000000000000008152fd5b86610faf565b871561100a57865b60c43590840310610fc157604097610fbb565b80610ff7565b915096506040813d604011611043575b8161102d6040938361568f565b810103126109105760208151910151965f610ebb565b3d9150611020565b6040513d85823e3d90fd5b9a7fffffff000000000000000000000000000000000000000000000000000000000060409b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000073ffffffffffffffffffffffffffffffffffffffff9a818c9a81610ea69a8d99610dfd565b8794610d8f565b505050949550505090505073ffffffffffffffffffffffffffffffffffffffff8916155f1461113057345b80156111085786888c8e95948d8a8e96610d86565b6004877f7c7f7bb9000000000000000000000000000000000000000000000000000000008152fd5b61113981615c6f565b6110f3565b5060a43515610d81565b8d8a73fffd8963efd1fc6a506488495d951d5263988d259a610d79565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc29550610d55565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc29150610d50565b6004867f203d82d8000000000000000000000000000000000000000000000000000000008152fd5b5060207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103745760043567ffffffffffffffff81116103725761121090369060040161559a565b9061121a82615922565b91611228604051938461568f565b8083527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061125582615922565b01845b8181106113cb5750509083907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301915b8381036113155784866040519182916020830160208452825180915260408401602060408360051b870101940192905b8282106112ca57505050500390f35b91936020611305827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0600195979984950301865288516155cb565b96019201920185949391926112bb565b8381101561139e57858160051b8301358481121561037257830180359067ffffffffffffffff82116109105760200190803603821361091057829181604051928392833781018381520390305af461136b615a6c565b901561139657906113919161138082886159c6565b5261138b81876159c6565b50615989565b61128b565b602081519101fd5b6024867f4e487b710000000000000000000000000000000000000000000000000000000081526032600452fd5b806060602080938801015201611258565b506101407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457611410615458565b61141861554b565b611420615507565b61142861549e565b9260e4359361012435421161119d57858573ffffffffffffffffffffffffffffffffffffffff806101243561145d8689615e8a565b9491909316928982168403611cf25760a4359360c4355b6040519561148187615673565b8652602086015260408501521660608301526044356080830152881580948195611ce9575b50611bd3575b84939291908315611bca578a5b8590604051903088528b60205260a4356040526060882090815c81811015611bb7575b50505060405215611aa7575b610124357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14611a91578a6d040470635eb91b7ce4d132d616ed945b73ffffffffffffffffffffffffffffffffffffffff8616906d08882d72efa6cce4b6a40b24c8608214611a6f575b156119045761164b9261161f916d040470635eb91b7ce4d132d616ed036118dc578a7f3c5eec5000000000000000000000000000000000000000000000000000000000965b60405196879560208701998a5261010435916024880192936101209473ffffffffffffffffffffffffffffffffffffffff939897969298608061014087019a80518852602081015160208901528660408201511660408901528660608201511660608901520151608087015260a086015260c0850152151560e0840152166101008201520152565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0810183528261568f565b73ffffffffffffffffffffffffffffffffffffffff88166118d55789905b51925af1611675615a6c565b90156118ad576020815191818082019384920101031261014957515b84156118a75794935b80611887575b1561186e57505073ffffffffffffffffffffffffffffffffffffffff81166116ec57506040925047806116dc575b505b82519182526020820152f35b6116e69033615b7c565b5f6116ce565b60a43561171f576040935061170081615c6f565b8061170d575b50506116d0565b611718913390615da8565b5f80611706565b6040517efdd58e00000000000000000000000000000000000000000000000000000000815230600482015260a435602482015260208160448173ffffffffffffffffffffffffffffffffffffffff86165afa908115611863578591611831575b5080611791575b5050604092506116d0565b6040517f095bcdb600000000000000000000000000000000000000000000000000000000815233600482015260a435602482015260448101919091529060209082906064908290889073ffffffffffffffffffffffffffffffffffffffff165af180156118265760409450611807575b80611786565b61181f9060203d6020116106e0576106d8818361568f565b505f611801565b6040513d86823e3d90fd5b90506020813d60201161185b575b8161184c6020938361568f565b8101031261014957515f61177f565b3d915061183f565b6040513d87823e3d90fd5b604095506118829250839060c43590615ae3565b6116d0565b503073ffffffffffffffffffffffffffffffffffffffff831614156116a0565b9361169a565b6004877f28982d61000000000000000000000000000000000000000000000000000000008152fd5b8390611669565b8a7f7466fde70000000000000000000000000000000000000000000000000000000096611597565b6119cb9261161f916d040470635eb91b7ce4d132d616ed03611a47578a7f38c3f8db000000000000000000000000000000000000000000000000000000009660405196879560208701998a5261010435916024880192936101209473ffffffffffffffffffffffffffffffffffffffff939897969298608061014087019a80518852602081015160208901528660408201511660408901528660608201511660608901520151608087015260a086015260c0850152151560e0840152166101008201520152565b73ffffffffffffffffffffffffffffffffffffffff8816611a405761010435905b51925af16119f8615a6c565b9015611a1857602081519181808201938492010103126101495751611691565b6004877fb4fff567000000000000000000000000000000000000000000000000000000008152fd5b83906119ec565b8a7fd4ff3f0e0000000000000000000000000000000000000000000000000000000096611597565b6080850180516bffffffffffffffffffffffff16905242610708019350611552565b8a6d08882d72efa6cce4b6a40b24c86094611524565b73ffffffffffffffffffffffffffffffffffffffff8916611ac8575b6114e8565b60a435611aee578315611ae257611ac38b5b30338c615bc7565b611ac361010435611ada565b73ffffffffffffffffffffffffffffffffffffffff94508315611ba8576020611b658a8d5b6040517ffe99049a00000000000000000000000000000000000000000000000000000000815233600482015230602482015260a4356044820152606481019190915297889283918b9183906084820190565b0393165af1948515611b9d578695611b7e575b506114e8565b611b969060203d6020116106e0576106d8818361568f565b505f611b78565b6040513d88823e3d90fd5b6020611b658a61010435611b13565b909192935003905d6001905f80806114dc565b610104356114b9565b98509192509073ffffffffffffffffffffffffffffffffffffffff8616611c2f5734975b8815611c075790899392916114ac565b60048a7f7c7f7bb9000000000000000000000000000000000000000000000000000000008152fd5b60a435611c4557611c3f86615c6f565b97611bf7565b6040517efdd58e00000000000000000000000000000000000000000000000000000000815230600482015260a435602482015260208160448173ffffffffffffffffffffffffffffffffffffffff8b165afa908115611cde578a91611cac575b5097611bf7565b90506020813d602011611cd6575b81611cc76020938361568f565b8101031261014957515f611ca5565b3d9150611cba565b6040513d8c823e3d90fd5b9050155f6114a6565b60c4359360a435611474565b5060207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103745760043567ffffffffffffffff811161037257611d4990369060040161555a565b6e04444c5dc75cb358380d2e3de08a90330361043257825c6109105781610120918101031261037257611d7b8161552a565b90611d886020820161552a565b90604081013590811593841583036121895760608201359162ffffff8316809303612332576080810135908160020b80920361232e57611dca60a0820161552a565b94611dd760c0830161552a565b9773ffffffffffffffffffffffffffffffffffffffff80808061010060e088013597013598169a169816991693848a108a1597815f14612326578c8c935b831561231f5788905b73ffffffffffffffffffffffffffffffffffffffff60405196611e4088615673565b16865273ffffffffffffffffffffffffffffffffffffffff602087019216825260408601938452606086019081526080860190838252885f146123165789935b5085156122fb576401000276a4945b60405193611e9c85615657565b87855260208501958652604085019673ffffffffffffffffffffffffffffffffffffffff168752604051987ff3cd914c000000000000000000000000000000000000000000000000000000008a525173ffffffffffffffffffffffffffffffffffffffff1660048a01525173ffffffffffffffffffffffffffffffffffffffff1660248901525162ffffff1660448801525160020b60648701525173ffffffffffffffffffffffffffffffffffffffff16608486015251151560a48501525160c48401525173ffffffffffffffffffffffffffffffffffffffff1660e4830152610104820161012090528b6101248301528b8233815a9361014492602095f19081156122f0578c916122a8575b6fffffffffffffffffffffffffffffffff92501561228c57821561228157165b905b333b1561227d578a6040517fa58411940000000000000000000000000000000000000000000000000000000081528b6004820152818160248183335af180156106e757612268575b505080156122615783995b6120298b8230615c9c565b1561223f578a881561222d575b50505b156122265780945b801515908161220e575b506121e65785156121d957600492602092156121d257505b604051928380927f11da60b4000000000000000000000000000000000000000000000000000000008252335af180156121c757612198575b5086333b15610374576040517f0b0d9c0900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff92831660048201529185166024830152604482018390528160648183335af1801561218d57612174575b506108bd955060405194602086015260408501526040845261212c60608561568f565b612147575b50506040519182916020835260208301906155cb565b47908115159081612169575b50156121315761216291615b7c565b5f80612131565b90503014155f612153565b61217f87809261568f565b6121895785612109565b8580fd5b6040513d89823e3d90fd5b6020813d6020116121bf575b816121b16020938361568f565b81010312610149575161209b565b3d91506121a4565b6040513d8a823e3d90fd5b9050612063565b5050506004602088612063565b60048a7f7dd37f70000000000000000000000000000000000000000000000000000000008152fd5b9050821561221f5781115b5f61204b565b8510612219565b8294612041565b612238913390615da8565b5f8a612036565b8a881561224e575b5050612039565b61225a918b3391615bc7565b5f8a612247565b819961201e565b816122729161568f565b61227d578a5f612013565b8a80fd5b60801d8b0316611fc9565b821561229d5760801d165b90611fcb565b600f0b8b0316612297565b90506020823d6020116122e8575b816122c36020938361568f565b810103126122e4576fffffffffffffffffffffffffffffffff915190611fa9565b8b80fd5b3d91506122b6565b6040513d8e823e3d90fd5b73fffd8963efd1fc6a506488495d951d5263988d2594611e8f565b89840393611e80565b8d90611e1e565b8c8793611e15565b8780fd5b8680fd5b5060c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610374578061236a615458565b6064359060ff8216809203610a5c5773ffffffffffffffffffffffffffffffffffffffff1690813b15610a5c57829160e4839260405194859384927fd505accf00000000000000000000000000000000000000000000000000000000845233600485015230602485015260243560448501526044356064850152608484015260843560a484015260a43560c48401525af180156106e7576124085750f35b816124129161568f565b6103745780f35b5060807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103745760043567ffffffffffffffff811161037257366023820112156103725780600401359067ffffffffffffffff8211610910576024808201918360061b010136811161281f5760643567ffffffffffffffff811161281b576124a990369060040161555a565b6124b285615922565b916124c0604051938461568f565b8583527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06124ed87615922565b01875b8181106127f8575050865b8681036127b657506040519361251085615657565b61251987615922565b90612527604051928361568f565b8782528690602083015b81831061277e575050508452602084019360243585526040810160443581526e22d473030f116ddee9f6b43ac78ba33b1561277a5790889594939291604051957f4da3e5d90000000000000000000000000000000000000000000000000000000087526080600488015260e4870192519260606084890152835180915260206101048901940190895b81811061272a575050505160a48701525160c48601527ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc85820301602486015260208085519283815201940190865b8181106126e0575050506126518593859384933360448601527ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8584030160648601526156d0565b0381836e22d473030f116ddee9f6b43ac78ba35af180156106e7576126cb575b5050825b828103612680578380f35b806126976126926126c6938686615a5c565b615788565b60206126a4838787615a5c565b013560405191308852602052866040526060872090815c01905d604052615989565b612675565b816126d59161568f565b61091057825f612671565b9195965091929360206040826127196001948a516020809173ffffffffffffffffffffffffffffffffffffffff81511684520151910152565b019601910191899695949392612609565b9195969798995091929360206040826127666001948a516020809173ffffffffffffffffffffffffffffffffffffffff81511684520151910152565b0196019101918c99989796959493926125ba565b8880fd5b60408336031261227d57602060409182516127988161560e565b6127a18661552a565b81528286013583820152815201920191612531565b8060206127c76127f3938a8a615a5c565b0135604051906127d68261560e565b30825260208201526127e882876159c6565b5261138b81866159c6565b6124fb565b6020906040516128078161560e565b8a81528a83820152828288010152016124f0565b8480fd5b8380fd5b5060e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457612856615458565b61285e61554b565b6128666154e4565b9161286f615507565b60843560a4359460c43590814211612e675773ffffffffffffffffffffffffffffffffffffffff84811615939291908116158481612e4b575b612e2f575b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8a9314612e26575b73ffffffffffffffffffffffffffffffffffffffff6128f58784615e8a565b9590919015908115612e0b57735c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f925b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000006040519181602084019460601b16845260601b1660348201526028815261296160488261568f565b5190209015612de5577f96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f5b604051917fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060208401947fff00000000000000000000000000000000000000000000000000000000000000865260601b16602184015260358301526055820152605581526129fb60758261568f565b51902016936040517f0902f1ac000000000000000000000000000000000000000000000000000000008152606081600481895afa9081156122f0578c908d92612d89575b508515612d72576dffffffffffffffffffffffffffff80915b169116995f14612cd057907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff612a9f926103e86103e584809e030293849202020101615a25565b988015908115612cc5575b50156121e6578389915b612abf838584615c9c565b15612c51575b505050505f14612ba9578115612ba25786305b823b156103725760a473ffffffffffffffffffffffffffffffffffffffff918360405195869485937f022c0d9f0000000000000000000000000000000000000000000000000000000085528360048601528c6024860152166044840152608060648401528160848401525af1801561218d57612b8d575b509483916040965b15612b705750506116d091612b6b82615d03565b615b7c565b6060925086519382526020528086522082815c01905d83526116d0565b612b9887809261568f565b612189575f612b4f565b8684612ad8565b8115612c4a5786305b823b156103725760a473ffffffffffffffffffffffffffffffffffffffff918360405195869485937f022c0d9f0000000000000000000000000000000000000000000000000000000085528c6004860152836024860152166044840152608060648401528160848401525af1801561218d57612c35575b50948391604096612b57565b612c4087809261568f565b612189575f612c29565b8684612bb2565b612c5c838530615c9c565b15612c745750612c6b92615da8565b5f878382612ac5565b15612cba57612c839250615e2f565b3073ffffffffffffffffffffffffffffffffffffffff861603612ca6575b612c6b565b86341115612ca157612ca187340333615b7c565b612ca1923390615bc7565b90508911155f612aaa565b99989080612d5e57508115612d4f5734995b8a15612d2757906103e5612d03926103e8828e5b02910201918c0202615a25565b978015908115612d1c575b50156121e657838991612ab4565b90508810155f612d0e565b60048c7f7c7f7bb9000000000000000000000000000000000000000000000000000000008152fd5b612d5883615c6f565b99612ce2565b906103e5809b6103e8612d03949d8e612cf6565b906dffffffffffffffffffffffffffff8091612a58565b9150506060813d606011612ddd575b81612da56060938361568f565b810103126122e457612db681615a0a565b6040612dc460208401615a0a565b92015163ffffffff811603612dd9575f612a3f565b8c80fd5b3d9150612d98565b7fe18a34eb0e04b04f7a0ac29a6e80748dca96319b42c54d679cb821dca90c630361298c565b73c0aee478e3658e2610c5f7a4a2e1777ce9e4f2ac92612918565b600192506128d6565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc295506128ad565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc292506128a8565b6004887f203d82d8000000000000000000000000000000000000000000000000000000008152fd5b5060e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457612ec2615458565b9060243590612ecf6154e4565b90612ed8615507565b9160843593612ee56154c1565b9560c43567ffffffffffffffff811161281b57612f0690369060040161555a565b909773ffffffffffffffffffffffffffffffffffffffff871698891593845f14613109578631955b73ffffffffffffffffffffffffffffffffffffffff821661309e575b505073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001691823b1561232e5791612fc993918893604051958694859384937f1cff79cd000000000000000000000000000000000000000000000000000000008552600485016159da565b039134905af1801561186357908591613089575b50612ff1929115905061307a5782316158ae565b9380851061304657506020945073ffffffffffffffffffffffffffffffffffffffff163014613025575b5050604051908152f35b606090604051923082528552806040522082815c01905d6040525f8061301b565b8260649186887f20768e08000000000000000000000000000000000000000000000000000000008452600452602452604452fd5b6130848386615e01565b6158ae565b816130939161568f565b61281f57835f612fdd565b8381156130b7576130b0923390615bc7565b5f80612f4a565b50506130c281615c6f565b9083600183116130d5575b5050506130b0565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff613101930191615da8565b5f80836130cd565b613113878a615e01565b95612f2e565b5060207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103745761314c615458565b6fa1903eab0000000000000000000000008252602082602460103473ae7ab96520de3a18e5e111b5eaab095312d7fe845af115610372578151906f8fcb4e5b0000000000000000000000008352601452806034528138604460108373ae7ab96520de3a18e5e111b5eaab095312d7fe845af11561037257602091603452604051908152f35b5060607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457613204615458565b61320c61554b565b6132146154e4565b9073ffffffffffffffffffffffffffffffffffffffff8454163303610c88571561329d5773ffffffffffffffffffffffffffffffffffffffff6044602092858360405196879586947f558a729700000000000000000000000000000000000000000000000000000000865216600485015260016024850152165af180156106e7576106bf575080f35b61049091615d2e565b5060e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610374576132d9615458565b6024356132e46154e4565b9060643567ffffffffffffffff811161281b5761330590369060040161559a565b60843567ffffffffffffffff81116123325761332590369060040161559a565b9561332e6154c1565b60c43567ffffffffffffffff81116136c257906133518a9392369060040161555a565b909261335c8761593a565b98855b8b898b818403613651575050505073ffffffffffffffffffffffffffffffffffffffff82166135e6575b505073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016803b1561281b57613405938593604051958694859384937f1cff79cd000000000000000000000000000000000000000000000000000000008552600485016159da565b039134905af180156106e7576135d1575b50506134248295949561593a565b9573ffffffffffffffffffffffffffffffffffffffff8516301495885b84810361348e57888a604051918291602083016020845282518091526020604085019301915b818110613475575050500390f35b8251845285945060209384019390920191600101613467565b73ffffffffffffffffffffffffffffffffffffffff6134b161269283888a6159b6565b166135b2576134cd87315b6134c683856159c6565b51906158ae565b6134d7828b6159c6565b526134e2818a6159c6565b516134ee8285876159b6565b351161354157613502908861350757615989565b613441565b61351561269282888a6159b6565b61351f828c6159c6565b51604051918d3090526020528c60405260608d2090815c01905d604052615989565b89939150613581818a9461357a8261357461269273ffffffffffffffffffffffffffffffffffffffff9760649c8e6159b6565b976159c6565b51946159b6565b35927f20768e0800000000000000000000000000000000000000000000000000000000855216600452602452604452fd5b6134cd6135cc886135c7612692858a8c6159b6565b615e01565b6134bc565b816135db9161568f565b61233257865f613416565b8381156135ff576135f8923390615bc7565b5f80613389565b505061360a81615c6f565b90836001831161361d575b5050506135f8565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff613649930191615da8565b5f8083613615565b90816136a095969798999a73ffffffffffffffffffffffffffffffffffffffff61368161269288868199986159b6565b16151590506136ac5750509050315b61369a828d6159c6565b52615989565b908c959493929161335f565b6136bd936135c792612692926159b6565b613690565b8980fd5b5060607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103745760043567ffffffffffffffff81116103725761371190369060040161555a565b60206137a561371e6154e4565b9260405183810190602435825273ffffffffffffffffffffffffffffffffffffffff861660408201526040815261375660608261568f565b5190209447916137668330615cd9565b50604051968794859384937fea9384fa0000000000000000000000000000000000000000000000000000000085526040600486015260448501916156d0565b90602483015203916e696760e15f265e828db644a0c242eb5af191821561104b578392613878575b50826e696760e15f265e828db644a0c242eb3b15610374576040517f23b872dd00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff9290921660248301526044820183905281606481836e696760e15f265e828db644a0c242eb5af1801561104b57613863575b602082604051908152f35b61386e83809261568f565b6103725781613858565b9091506020813d6020116138a4575b816138946020938361568f565b810103126101495751905f6137cd565b3d9150613887565b5060a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610374578060443560ff8116809103610a5757736b175474e89094c44da98b954eedeac495271d0f3b15610a5757604051907f8fcbaf0c000000000000000000000000000000000000000000000000000000008252336004830152306024830152600435604483015260243560648301526001608483015260a482015260643560c482015260843560e482015281816101048183736b175474e89094c44da98b954eedeac495271d0f5af180156106e7576124085750f35b506101207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610374576139bf615458565b6139c761554b565b6139cf615588565b606435908160020b80920361281b576139e661549e565b926139ef6154c1565b9360c43592610104354211612e675787939215929190838381613c18575b50613ba8575b90613ad29562ffffff73ffffffffffffffffffffffffffffffffffffffff9360405196336020890152858c16604089015215606088015216608086015260a08501521660c083015273ffffffffffffffffffffffffffffffffffffffff851660e083015261010082015260e4356101208201526101208152613a976101408261568f565b604051809381927f48c894910000000000000000000000000000000000000000000000000000000083526020600484015260248301906155cb565b0381836e04444c5dc75cb358380d2e3de08a905af1908115611826578491613b30575b5060408180518101031261281f5760606040948560208401519301519386519582526020528086522082815c01905d82845282526020820152f35b9050833d8082843e613b42818461568f565b8201916020818403126103725780519067ffffffffffffffff8211610910570182601f82011215610372578051613b78816158e8565b93613b86604051958661568f565b81855260208284010111610910578060208093018386015e830101525f613af5565b9390929491505073ffffffffffffffffffffffffffffffffffffffff8216155f14613c095734925b8315613be157918793919492613a13565b6004887f7c7f7bb9000000000000000000000000000000000000000000000000000000008152fd5b613c1282615c6f565b92613bd0565b9050155f613a0d565b50346103745760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457613c59615458565b50613c6261547b565b5060643567ffffffffffffffff811161037257613c8390369060040161555a565b505060206040517f150b7a02000000000000000000000000000000000000000000000000000000008152f35b506105207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457613ce3615458565b90613cec61554b565b91366101a41161037257366104241161037257366104c411610372576104c435926104e43591610504354211614fb557613d24615765565b91849182805b60058110614f63575b5073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8514851517938897845f14614ed75760018201805b6148245750871515888a8261481a575b50506147f2575b85156147ec5773c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2965b613d9d8a8930615c9c565b1561479d575b918992823060601b915b8382111561400a57505050508415998a5f14613ff45782988015159081613fea575b50613fc25760409a5b15613f065750821573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee84141715613eba5750613e09915082615b7c565b81613e99575b50613e23575b505082519182526020820152f35b15613e7157504780613e61575b50613e39615c2e565b80613e48575b505b5f80613e15565b80613e55613e5b92615d03565b33615b7c565b5f613e3f565b613e6b9033615b7c565b5f613e30565b613e7a81615c6f565b80613e87575b5050613e41565b613e92913390615da8565b5f80613e80565b73ffffffffffffffffffffffffffffffffffffffff1630141590505f613e0f565b8373ffffffffffffffffffffffffffffffffffffffff81163003613ef657506060908a5193858252602052808b522090815c01905d8752613e09565b9050613f0192615da8565b613e09565b909181613f12916158ae565b91831573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee85141715613f5b5750613f3f91925083615b7c565b80613f4b575b50613e09565b613f559033615b7c565b5f613f45565b9073ffffffffffffffffffffffffffffffffffffffff85163003613fb15760608b519286815285602052808d522090815c01905d89525b80613f9f575b5050613e09565b613faa913390615da8565b5f80613f98565b613fbd91508484615da8565b613f92565b6004827f7dd37f70000000000000000000000000000000000000000000000000000000008152fd5b905083105f613dcf565b80919a985082106121e657988960409a98613dd8565b61401b612692600184811b01615726565b61402d6126926001850160011b615726565b9661403f61403a856157a9565b6157bc565b60408101516060820151946008821461466f57801573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8214171561466a575073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25b846040518160405289602c526fdd62ed3e000000000000000000000000600c526020806044601c865afa601f3d111660205102906040521561465a575b5050891573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8b141793841561464b5747955b8a6001840361427a575073ffffffffffffffffffffffffffffffffffffffff9250600a036141f657169060208151600f0b910151600f0b90823b156136c2576040517f3df02124000000000000000000000000000000000000000000000000000000008152600f91820b600482015291900b602482015260448101929092525f606483015287908290608490829084905af1801561218d579087916141e1575b50505b156141d357475b818111156141ab570394906001905b0190613dad565b6004867f7c7f7bb9000000000000000000000000000000000000000000000000000000008152fd5b6141dc86615c6f565b614195565b816141eb9161568f565b61218957855f61418b565b16906020815191015191803b156136c2578992918360849260405196879586947f5b41b9080000000000000000000000000000000000000000000000000000000086526004860152602485015260448401528160648401525af1801561218d57908791614265575b505061418e565b8161426f9161568f565b61218957855f61425e565b91926002810361431a5750505073ffffffffffffffffffffffffffffffffffffffff169060208151600f0b910151600f0b90823b156136c2576040517fa6417ed6000000000000000000000000000000000000000000000000000000008152600f91820b600482015291900b602482015260448101929092525f606483015287908290608490829084905af1801561218d5790879161426557505061418e565b9294939192600481036145565750600a81036143f157506040516020936143a8936101249361435c9161010090614351828761568f565b503685375183615876565b528a73ffffffffffffffffffffffffffffffffffffffff60405196879586947f52d7f3170000000000000000000000000000000000000000000000000000000086526004860190615887565b82610104850152165af1801561218d576143c3575b5061418e565b6143e39060203d81116143ea575b6143db818361568f565b810190615808565b505f6143bd565b503d6143d1565b90919060148103614497575060648160209394614473935061442860409687519361441c898661568f565b5087368537518361583e565b528b73ffffffffffffffffffffffffffffffffffffffff865197889586947f0b4c7e4d000000000000000000000000000000000000000000000000000000008652600486019061584f565b826044850152165af190811561448e57506143c3575061418e565b513d89823e3d90fd5b601e1415905061452e576084896020936144c9614515946060604051946144be828761568f565b5036853751836157f7565b528a73ffffffffffffffffffffffffffffffffffffffff60405196879586947f4515cef30000000000000000000000000000000000000000000000000000000086526004860190615817565b826064850152165af1801561218d576143c3575061418e565b6004897f7c7f7bb9000000000000000000000000000000000000000000000000000000008152fd5b9194925090600603611c075760209173ffffffffffffffffffffffffffffffffffffffff91600a036145e85716920151600f0b90823b1561277a5790606489928360405195869485937f1a4d01d2000000000000000000000000000000000000000000000000000000008552600485015260248401528160448401525af1801561218d5790879161426557505061418e565b1692015190823b1561277a5790606489928360405195869485937ff1dc3cc9000000000000000000000000000000000000000000000000000000008552600485015260248401528160448401525af1801561218d5790879161426557505061418e565b6146548b615c6f565b956140eb565b61466391615d2e565b5f846140c5565b614088565b9350505096915073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81148115178061476a575b156146fd575050806146c0575b600173c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2916141a4565b8447106146d5576146d085615a9b565b6146a3565b6004847f7c7f7bb9000000000000000000000000000000000000000000000000000000008152fd5b73ffffffffffffffffffffffffffffffffffffffff1673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2149081614748575b50156146d55761473f85615d03565b600184916141a4565b905073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81149015175f614730565b5073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff831614614696565b86156147e0578934106147b8576147b38a615a9b565b613da3565b6004827f85cf0a35000000000000000000000000000000000000000000000000000000008152fd5b6147b38a30338b615bc7565b86613d92565b807f7dd37f700000000000000000000000000000000000000000000000000000000060049252fd5b119050885f613d6e565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01614857612692600183811b01615726565b61486361403a836157a9565b604081015160608201519060088103614881575b5050505080613d5e565b939c93600181036149fa5750600a0361494b5780516020918201516040517f67df02ca000000000000000000000000000000000000000000000000000000008152600f92830b6004820152910b60248201526044810193909352908290606490829073ffffffffffffffffffffffffffffffffffffffff165afa9081156106e757908a918391614917575b50995b5f8080614877565b9150506020813d8211614943575b816149326020938361568f565b81010312610149578990515f61490c565b3d9150614925565b80516020918201516040517f37ed3a7a000000000000000000000000000000000000000000000000000000008152600481019290925260248201526044810193909352908290606490829073ffffffffffffffffffffffffffffffffffffffff165afa9081156106e757908a9183916149c6575b509961490f565b9150506020813d82116149f2575b816149e16020938361568f565b81010312610149578990515f6149bf565b3d91506149d4565b9193929160028103614ba157505060208351600f0b930151600f0b9084841380614b98575b15614b1d575060058c1015614af0576020917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8092614ad58f614a7d73ffffffffffffffffffffffffffffffffffffffff9160051b61042401615788565b1693604051978896879586957f67df02ca00000000000000000000000000000000000000000000000000000000875201600f0b9101600f0b600485016040919493926060820195600f0b8252600f0b60208201520152565b03915afa9081156106e757908a9183916149c657509961490f565b6024847f4e487b710000000000000000000000000000000000000000000000000000000081526032600452fd5b6040517f0e71d1b9000000000000000000000000000000000000000000000000000000008152600f94850b60048201529190930b60248201526044810191909152906020908290606490829073ffffffffffffffffffffffffffffffffffffffff165afa9081156106e757908a9183916149c657509961490f565b50848213614a1f565b9293919260048103614cc357506020929391600a604492145f14614c295751600f0b9173ffffffffffffffffffffffffffffffffffffffff60405195869485937fcc2b27d700000000000000000000000000000000000000000000000000000000855260048501526024840152165afa9081156106e757908a9183916149c657505b9961490f565b519173ffffffffffffffffffffffffffffffffffffffff60405195869485937f4fb08c5e00000000000000000000000000000000000000000000000000000000855260048501526024840152165afa9081156106e757908a918391614c8f575b50614c23565b9150506020813d8211614cbb575b81614caa6020938361568f565b81010312610149578990515f614c89565b3d9150614c9d565b600603614eaf57600a8103614d6b5750610124614d4a9160209394614cff856101009360405194614cf4818761568f565b368637015183615876565b5273ffffffffffffffffffffffffffffffffffffffff60405195869485937f2f0149080000000000000000000000000000000000000000000000000000000085526004850190615887565b87610104840152165afa9081156106e757908a9183916149c657509961490f565b60148103614e105750614de66064602092604095614d9c85885193614d908a8661568f565b8936863701518361583e565b5273ffffffffffffffffffffffffffffffffffffffff865195869485937fed8e84f3000000000000000000000000000000000000000000000000000000008552600485019061584f565b886044840152165afa918215614e075750908a9183916149c657509961490f565b513d84823e3d90fd5b91929091601e036146d5576084602092614e8f92614e448560609360405194614e39818761568f565b3686370151836157f7565b5273ffffffffffffffffffffffffffffffffffffffff60405195869485937f3883e1190000000000000000000000000000000000000000000000000000000085526004850190615817565b876064840152165afa9081156106e757908a9183916149c657509961490f565b6004857f7c7f7bb9000000000000000000000000000000000000000000000000000000008152fd5b975088614f23578415614f145734975b88613d7557807f7c7f7bb90000000000000000000000000000000000000000000000000000000060049252fd5b614f1d86615c6f565b97614ee7565b88978580614f59575b15613d7557807f85cf0a350000000000000000000000000000000000000000000000000000000060049252fd5b5089341415614f2c565b939073ffffffffffffffffffffffffffffffffffffffff614f8b612692600188811b01615726565b1615614fae575050614fa56126926001850160011b615726565b60018401613d2a565b9093613d33565b6004847f203d82d8000000000000000000000000000000000000000000000000000000008152fd5b5060607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457615010615458565b34159060443560243583156150fb575b73ffffffffffffffffffffffffffffffffffffffff83169384151590816150f3575b50615054575b61049093503092615ae3565b8061506f57610490935061506a82303386615bc7565b615048565b6040517ffe99049a0000000000000000000000000000000000000000000000000000000081523360048201523060248201526044810182905260648101839052936020908590608490829089905af193841561186357610490946150d4575b50615048565b6150ec9060203d6020116106e0576106d8818361568f565b505f6150ce565b90505f615042565b806151aa5773ffffffffffffffffffffffffffffffffffffffff831673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2810361517057508134036151485761514382615afe565b615020565b6004857f85cf0a35000000000000000000000000000000000000000000000000000000008152fd5b6151a457815b3414615020576004857f85cf0a35000000000000000000000000000000000000000000000000000000008152fd5b84615176565b6004857fdfa1a408000000000000000000000000000000000000000000000000000000008152fd5b5060a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261014957615205615458565b6024359060843567ffffffffffffffff81116101495761522990369060040161555a565b604051916152368361560e565b73ffffffffffffffffffffffffffffffffffffffff841683528460208401526040519261526284615657565b83526020830192604435845260408101916064358352604051906152858261560e565b3082528760208301526e22d473030f116ddee9f6b43ac78ba33b15610149575f9461533b6153549361530796604051998a9889987f30f28b7a000000000000000000000000000000000000000000000000000000008a5260048a0190516020809173ffffffffffffffffffffffffffffffffffffffff81511684520151910152565b516044880152516064870152805173ffffffffffffffffffffffffffffffffffffffff1660848701526020015160a4860152565b3360c485015261010060e48501526101048401916156d0565b0381836e22d473030f116ddee9f6b43ac78ba35af180156153a15761538c575b50308352602052816040526060822090815c01905d80f35b6153999193505f9061568f565b5f915f615374565b6040513d5f823e3d90fd5b60407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610149576153de615458565b6153e661554b565b9073ffffffffffffffffffffffffffffffffffffffff5f541633036100f05773ffffffffffffffffffffffffffffffffffffffff165f52600160205260405f209060ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00835416911515161790555f80f35b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361014957565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361014957565b6084359073ffffffffffffffffffffffffffffffffffffffff8216820361014957565b60a4359073ffffffffffffffffffffffffffffffffffffffff8216820361014957565b6044359073ffffffffffffffffffffffffffffffffffffffff8216820361014957565b6064359073ffffffffffffffffffffffffffffffffffffffff8216820361014957565b359073ffffffffffffffffffffffffffffffffffffffff8216820361014957565b60243590811515820361014957565b9181601f840112156101495782359167ffffffffffffffff8311610149576020838186019501011161014957565b6044359062ffffff8216820361014957565b9181601f840112156101495782359167ffffffffffffffff8311610149576020808501948460051b01011161014957565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602080948051918291828752018686015e5f8582860101520116010190565b6040810190811067ffffffffffffffff82111761562a57604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6060810190811067ffffffffffffffff82111761562a57604052565b60a0810190811067ffffffffffffffff82111761562a57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761562a57604052565b601f82602094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe093818652868601375f8582860101520116010190565b90816020910312610149575180151581036101495790565b600b8110156157385760051b60440190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b60443573ffffffffffffffffffffffffffffffffffffffff811681036101495790565b3573ffffffffffffffffffffffffffffffffffffffff811681036101495790565b60058110156157385760071b6101a40190565b604051906157cb60808361568f565b81608082019136831161014957905b8282106157e75750505090565b81358152602091820191016157da565b9060038110156157385760051b0190565b90816020910312610149575190565b905f905b6003821061582857505050565b602080600192855181520193019101909161581b565b9060028110156157385760051b0190565b905f905b6002821061586057505050565b6020806001928551815201930191019091615853565b9060088110156157385760051b0190565b905f905b6008821061589857505050565b602080600192855181520193019101909161588b565b919082039182116158bb57565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b67ffffffffffffffff811161562a57601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b67ffffffffffffffff811161562a5760051b60200190565b9061594482615922565b615951604051918261568f565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061597f8294615922565b0190602036910137565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146158bb5760010190565b91908110156157385760051b0190565b80518210156157385760209160051b010190565b60409073ffffffffffffffffffffffffffffffffffffffff615a07959316815281602082015201916156d0565b90565b51906dffffffffffffffffffffffffffff8216820361014957565b8115615a2f570490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b91908110156157385760061b0190565b3d15615a96573d90615a7d826158e8565b91615a8b604051938461568f565b82523d5f602084013e565b606090565b80615ade5750475b615aac81615afe565b60405190305f5273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26020525f60405260605f2090815c01905d604052565b615aa3565b604051935f5260205260405260605f2090815c01905d604052565b3073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc214615b4a575f908180389273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25af115615b3d57565b63b12d13eb5f526004601cfd5b6040519073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25f525f6020525f60405260605f2090815c01905d604052565b903073ffffffffffffffffffffffffffffffffffffffff831614615baa57905f80809338935af115615b3d57565b604051915f525f6020525f60405260605f2090815c01905d604052565b916040519360605260405260601b602c526f23b872dd000000000000000000000000600c5260205f6064601c82855af1908160015f51141615615c10575b50505f606052604052565b3b153d171015615c21575f80615c05565b637939f4245f526004601cfd5b306014526f70a082310000000000000000000000005f526020806024601073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25afa601f3d11166020510290565b6020602460108293306014526f70a082310000000000000000000000005f525afa601f3d11166020510290565b9092915f93604051925f526020525f60405260605f2090815c81811015615cc6575b505050604052565b909192945003905d6001915f8080615cbe565b9190915f92604051915f525f6020525f60405260605f2090815c81811015615cc657505050604052565b632e1a7d4d5f526020525f386024601c8373c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25af150565b906014527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6034526f095ea7b30000000000000000000000005f5260205f6044601082855af1908160015f51141615615d8a575b50505f603452565b3b153d171015615d9b575f80615d82565b633e3f8f735f526004601cfd5b91906014526034526fa9059cbb0000000000000000000000005f5260205f6044601082855af1908160015f51141615615de35750505f603452565b3b153d171015615df4575f80615d82565b6390b8ec185f526004601cfd5b602460106020939284936014526f70a082310000000000000000000000005f525afa601f3d11166020510290565b5f3881808573c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25af1506014526034526fa9059cbb0000000000000000000000005f525f38604460108373c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25af1505f603452565b73ffffffffffffffffffffffffffffffffffffffff821673ffffffffffffffffffffffffffffffffffffffff82161090815f14615ec45792565b9192565b606091615ed491615e8a565b9390604051928352602083015260408201522060ff5f537fe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b546035527f1f98431c8ad98523631ae4a59f267346ea31f98400000000000000000000000060015260155260555f205f6035529156fea2646970667358221220680d3856dd5dd9a45a7a5d84fcf6d844dbc78e980b32ee2b70e49457f3162b8964736f6c634300082100336080806040523460145760fc90816100198239f35b5f80fdfe60808060405260043610156011575f80fd5b5f3560e01c631cff79cd146023575f80fd5b60407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011260c25760043573ffffffffffffffffffffffffffffffffffffffff8116810360c2576024359067ffffffffffffffff821160c2573660238301121560c257816004013567ffffffffffffffff811160c257366024828501011160c2578060245f9401853783389234905af11560ba57005b3d5f823e3d90fd5b5f80fdfea26469706673582212200f5b73cf8afffc1fc335ed24633eddf2915c1ffea4db11019ab1228a477a388b64736f6c63430008210033

Deployed Bytecode

0x6080604052600436101561014d575b36156100b7575f5c61014957609a3560601c6024356004358015801590610140575b156101185761004a60d63560e81c60ae3560601c85615ec8565b939073ffffffffffffffffffffffffffffffffffffffff811633036100f05784156100e95782905b61007d828430615c9c565b156100c05761008b92615da8565b6085355f1a61009657005b6100b792156100b957505b5f036100ac81615d03565b60c23560601c615b7c565b005b90506100a1565b6084355f1a156100d9576100d49250615e2f565b61008b565b6100d49260863560601c90615bc7565b8390610072565b7f82b42900000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f7c7f7bb9000000000000000000000000000000000000000000000000000000005f5260045ffd5b50811515610030565b5f80fd5b5f5f3560e01c806306262f1b146153ac57806309d31579146151d25780630efe6a8b14614fdd57806312db224a14613caf578063150b7a0214613c2157806321c0dad21461398b578063230390f4146138ac5780632cb9f974146136c65780633f896275146132a657806341abb1ef146131d157806347c1ba3a146131195780635f3bd1c814612e8f5780636e0a4f98146128235780637984d8b1146124195780637ac2ff7b1461233657806391dd734614611cfe5780639d5b5af8146113dc578063ac9650d8146111c5578063afeae12b14610cb0578063b61d27f614610b92578063bd6b76d714610a60578063c391b38114610914578063c42957a81461073e578063cb019b841461054f578063de0e9a3e14610502578063e8382b0114610493578063ea598cb01461045a578063f2fde38b146103775763f978602c14610297575061000e565b60207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610374576102c9615458565b8138818034737f39c581f595b53c5cb19bd0b3f8da6c935e2ca05af11561037257306014526f70a08231000000000000000000000000825260208260246010737f39c581f595b53c5cb19bd0b3f8da6c935e2ca05afa15610372578151906fa9059cbb00000000000000000000000083526014528060345281386044601083737f39c581f595b53c5cb19bd0b3f8da6c935e2ca05af11561037257602091603452604051908152f35b505b80fd5b5060207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610374576103aa615458565b81549073ffffffffffffffffffffffffffffffffffffffff82163303610432579073ffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffff0000000000000000000000000000000000000000921691829116178255337f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b6004837f82b42900000000000000000000000000000000000000000000000000000000008152fd5b5060207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457610490600435615a9b565b80f35b503461037457807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457602060405173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000025fc36455aa30d012bbfb86f283975440d7ee8db168152f35b5060207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457600435806105465750610490610541615c2e565b615d03565b61049090615d03565b5060807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457610582615458565b60243590604435610591615507565b9173ffffffffffffffffffffffffffffffffffffffff8116806105c85750610490935050806105c257504790615b7c565b90615b7c565b9092919085856105ee5750610490945050806105e857506105e882615c6f565b91615da8565b92935091908061072e57506040517efdd58e00000000000000000000000000000000000000000000000000000000815230600482015260248101859052602081604481865afa9081156106e75782916106f2575b509360209392916106ac95935b604051968795869485937f095bcdb60000000000000000000000000000000000000000000000000000000085526004850160409194939273ffffffffffffffffffffffffffffffffffffffff606083019616825260208201520152565b03925af180156106e7576106bf575b5080f35b6106bb9060203d6020116106e0575b6106d8818361568f565b81019061570e565b503d6106ce565b6040513d84823e3d90fd5b93929150506020833d602011610726575b816107106020938361568f565b8101031261014957915190919084906020610642565b3d9150610703565b9360209392916106ac959361064f565b507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360161016081126103725760a0136103745760a4356101243573ffffffffffffffffffffffffffffffffffffffff81168091036109105760609073ffffffffffffffffffffffffffffffffffffffff6107b7615765565b1661090657610164835b60405194859384927fc42957a80000000000000000000000000000000000000000000000000000000084526004356004850152602435602485015273ffffffffffffffffffffffffffffffffffffffff6108196154e4565b16604485015273ffffffffffffffffffffffffffffffffffffffff61083c615507565b166064850152608435608485015260a484015260c43560c484015260e43560e484015261010435610104840152610124830152610144356101448301526d040470635eb91b7ce4d132d616ed5af180156106e75782918380926108c1575b50506108bd90604051938493846040919493926060820195825260208201520152565b0390f35b92509250506060823d6060116108fe575b816108df6060938361568f565b810103126103745750805160208201516040909201516108bd5f61089a565b3d91506108d2565b61016484936107c1565b8280fd5b5060407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103745780610948615458565b6024356fd5002f2e00000000000000000000000083526020836004601073ae7ab96520de3a18e5e111b5eaab095312d7fe845afa15610a5c5782516f37cfdaca00000000000000000000000084526020846004601073ae7ab96520de3a18e5e111b5eaab095312d7fe845afa15610a5a578351820290808204910615150191348311610a5a578338818086737f39c581f595b53c5cb19bd0b3f8da6c935e2ca05af115610a5a576fa9059cbb000000000000000000000000845260145260345281386044601083737f39c581f595b53c5cb19bd0b3f8da6c935e2ca05af115610a575781603452803411610a395750f35b818038923403335af115610a4a5780f35b63b12d13eb90526004601cfd5b50fd5b505b5050fd5b5060407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103745780610a94615458565b6fd5002f2e00000000000000000000000082526020826004601073ae7ab96520de3a18e5e111b5eaab095312d7fe845afa15610a575781516f37cfdaca00000000000000000000000083526020836004601073ae7ab96520de3a18e5e111b5eaab095312d7fe845afa15610a5c57825190806024350282808204910615150191820290808204910615150191348311610a5a57833881808673ae7ab96520de3a18e5e111b5eaab095312d7fe845af115610a5a576f8fcb4e5b00000000000000000000000084526014526034528138604460108373ae7ab96520de3a18e5e111b5eaab095312d7fe845af115610a575781603452803411610a395750f35b5060607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457610bc5615458565b60443567ffffffffffffffff811161091057610be590369060040161555a565b73ffffffffffffffffffffffffffffffffffffffff839293168452600160205260ff60408520541615610c88579083916001835d80604051948537833892602435905af115610c7f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0903d81523d83602083013e610c7a3d820191602083019485604052805d6020855260408301906155cb565b030190f35b903d90823e3d90fd5b6004847f82b42900000000000000000000000000000000000000000000000000000000008152fd5b506101007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457610ce4615458565b610cec61554b565b90610cf5615588565b90610cfe615507565b91610d0761549e565b60e435421161119d5794849560a435819373ffffffffffffffffffffffffffffffffffffffff87931615928373ffffffffffffffffffffffffffffffffffffffff891615611181575b611165575b808786610d64858a8096615ec8565b9d8e9591948615611148578d8a6401000276a49a5b84158061113e575b6110c8575b81156110c15730945b156110565786039a7fffffff000000000000000000000000000000000000000000000000000000000060409b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000073ffffffffffffffffffffffffffffffffffffffff9a818c9a81610ea69a8d995b60408b90519c161560f81b60208d015260f81b60218c01523360601b60228c015260601b1660368a015260601b16604a88015260601b16605e86015260e81b16607284015260558352610e5160758461568f565b8a519b8c9a8b998a977f128acb0800000000000000000000000000000000000000000000000000000000895216600488015215156024870152604486015216606484015260a0608484015260a48301906155cb565b0393165af196871561104b5783918498611010575b5060c435610fa2575b5060409715610f865773ffffffffffffffffffffffffffffffffffffffff905b838112610f7e57965b838113610f78578303955b1615610f33575b15610f14575b50505082519182526020820152f35b60609186519382526020528086522082815c01905d83525f8080610f05565b4780151580610f58575b610f48575b50610eff565b610f529033615b7c565b5f610f42565b503073ffffffffffffffffffffffffffffffffffffffff86161415610f3d565b95610ef8565b830396610eed565b9573ffffffffffffffffffffffffffffffffffffffff90610ee4565b15610fef578715610fe957805b60c43510610fc1576040975b97610ec4565b6004837f7dd37f70000000000000000000000000000000000000000000000000000000008152fd5b86610faf565b871561100a57865b60c43590840310610fc157604097610fbb565b80610ff7565b915096506040813d604011611043575b8161102d6040938361568f565b810103126109105760208151910151965f610ebb565b3d9150611020565b6040513d85823e3d90fd5b9a7fffffff000000000000000000000000000000000000000000000000000000000060409b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000073ffffffffffffffffffffffffffffffffffffffff9a818c9a81610ea69a8d99610dfd565b8794610d8f565b505050949550505090505073ffffffffffffffffffffffffffffffffffffffff8916155f1461113057345b80156111085786888c8e95948d8a8e96610d86565b6004877f7c7f7bb9000000000000000000000000000000000000000000000000000000008152fd5b61113981615c6f565b6110f3565b5060a43515610d81565b8d8a73fffd8963efd1fc6a506488495d951d5263988d259a610d79565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc29550610d55565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc29150610d50565b6004867f203d82d8000000000000000000000000000000000000000000000000000000008152fd5b5060207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103745760043567ffffffffffffffff81116103725761121090369060040161559a565b9061121a82615922565b91611228604051938461568f565b8083527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061125582615922565b01845b8181106113cb5750509083907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301915b8381036113155784866040519182916020830160208452825180915260408401602060408360051b870101940192905b8282106112ca57505050500390f35b91936020611305827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0600195979984950301865288516155cb565b96019201920185949391926112bb565b8381101561139e57858160051b8301358481121561037257830180359067ffffffffffffffff82116109105760200190803603821361091057829181604051928392833781018381520390305af461136b615a6c565b901561139657906113919161138082886159c6565b5261138b81876159c6565b50615989565b61128b565b602081519101fd5b6024867f4e487b710000000000000000000000000000000000000000000000000000000081526032600452fd5b806060602080938801015201611258565b506101407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457611410615458565b61141861554b565b611420615507565b61142861549e565b9260e4359361012435421161119d57858573ffffffffffffffffffffffffffffffffffffffff806101243561145d8689615e8a565b9491909316928982168403611cf25760a4359360c4355b6040519561148187615673565b8652602086015260408501521660608301526044356080830152881580948195611ce9575b50611bd3575b84939291908315611bca578a5b8590604051903088528b60205260a4356040526060882090815c81811015611bb7575b50505060405215611aa7575b610124357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14611a91578a6d040470635eb91b7ce4d132d616ed945b73ffffffffffffffffffffffffffffffffffffffff8616906d08882d72efa6cce4b6a40b24c8608214611a6f575b156119045761164b9261161f916d040470635eb91b7ce4d132d616ed036118dc578a7f3c5eec5000000000000000000000000000000000000000000000000000000000965b60405196879560208701998a5261010435916024880192936101209473ffffffffffffffffffffffffffffffffffffffff939897969298608061014087019a80518852602081015160208901528660408201511660408901528660608201511660608901520151608087015260a086015260c0850152151560e0840152166101008201520152565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0810183528261568f565b73ffffffffffffffffffffffffffffffffffffffff88166118d55789905b51925af1611675615a6c565b90156118ad576020815191818082019384920101031261014957515b84156118a75794935b80611887575b1561186e57505073ffffffffffffffffffffffffffffffffffffffff81166116ec57506040925047806116dc575b505b82519182526020820152f35b6116e69033615b7c565b5f6116ce565b60a43561171f576040935061170081615c6f565b8061170d575b50506116d0565b611718913390615da8565b5f80611706565b6040517efdd58e00000000000000000000000000000000000000000000000000000000815230600482015260a435602482015260208160448173ffffffffffffffffffffffffffffffffffffffff86165afa908115611863578591611831575b5080611791575b5050604092506116d0565b6040517f095bcdb600000000000000000000000000000000000000000000000000000000815233600482015260a435602482015260448101919091529060209082906064908290889073ffffffffffffffffffffffffffffffffffffffff165af180156118265760409450611807575b80611786565b61181f9060203d6020116106e0576106d8818361568f565b505f611801565b6040513d86823e3d90fd5b90506020813d60201161185b575b8161184c6020938361568f565b8101031261014957515f61177f565b3d915061183f565b6040513d87823e3d90fd5b604095506118829250839060c43590615ae3565b6116d0565b503073ffffffffffffffffffffffffffffffffffffffff831614156116a0565b9361169a565b6004877f28982d61000000000000000000000000000000000000000000000000000000008152fd5b8390611669565b8a7f7466fde70000000000000000000000000000000000000000000000000000000096611597565b6119cb9261161f916d040470635eb91b7ce4d132d616ed03611a47578a7f38c3f8db000000000000000000000000000000000000000000000000000000009660405196879560208701998a5261010435916024880192936101209473ffffffffffffffffffffffffffffffffffffffff939897969298608061014087019a80518852602081015160208901528660408201511660408901528660608201511660608901520151608087015260a086015260c0850152151560e0840152166101008201520152565b73ffffffffffffffffffffffffffffffffffffffff8816611a405761010435905b51925af16119f8615a6c565b9015611a1857602081519181808201938492010103126101495751611691565b6004877fb4fff567000000000000000000000000000000000000000000000000000000008152fd5b83906119ec565b8a7fd4ff3f0e0000000000000000000000000000000000000000000000000000000096611597565b6080850180516bffffffffffffffffffffffff16905242610708019350611552565b8a6d08882d72efa6cce4b6a40b24c86094611524565b73ffffffffffffffffffffffffffffffffffffffff8916611ac8575b6114e8565b60a435611aee578315611ae257611ac38b5b30338c615bc7565b611ac361010435611ada565b73ffffffffffffffffffffffffffffffffffffffff94508315611ba8576020611b658a8d5b6040517ffe99049a00000000000000000000000000000000000000000000000000000000815233600482015230602482015260a4356044820152606481019190915297889283918b9183906084820190565b0393165af1948515611b9d578695611b7e575b506114e8565b611b969060203d6020116106e0576106d8818361568f565b505f611b78565b6040513d88823e3d90fd5b6020611b658a61010435611b13565b909192935003905d6001905f80806114dc565b610104356114b9565b98509192509073ffffffffffffffffffffffffffffffffffffffff8616611c2f5734975b8815611c075790899392916114ac565b60048a7f7c7f7bb9000000000000000000000000000000000000000000000000000000008152fd5b60a435611c4557611c3f86615c6f565b97611bf7565b6040517efdd58e00000000000000000000000000000000000000000000000000000000815230600482015260a435602482015260208160448173ffffffffffffffffffffffffffffffffffffffff8b165afa908115611cde578a91611cac575b5097611bf7565b90506020813d602011611cd6575b81611cc76020938361568f565b8101031261014957515f611ca5565b3d9150611cba565b6040513d8c823e3d90fd5b9050155f6114a6565b60c4359360a435611474565b5060207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103745760043567ffffffffffffffff811161037257611d4990369060040161555a565b6e04444c5dc75cb358380d2e3de08a90330361043257825c6109105781610120918101031261037257611d7b8161552a565b90611d886020820161552a565b90604081013590811593841583036121895760608201359162ffffff8316809303612332576080810135908160020b80920361232e57611dca60a0820161552a565b94611dd760c0830161552a565b9773ffffffffffffffffffffffffffffffffffffffff80808061010060e088013597013598169a169816991693848a108a1597815f14612326578c8c935b831561231f5788905b73ffffffffffffffffffffffffffffffffffffffff60405196611e4088615673565b16865273ffffffffffffffffffffffffffffffffffffffff602087019216825260408601938452606086019081526080860190838252885f146123165789935b5085156122fb576401000276a4945b60405193611e9c85615657565b87855260208501958652604085019673ffffffffffffffffffffffffffffffffffffffff168752604051987ff3cd914c000000000000000000000000000000000000000000000000000000008a525173ffffffffffffffffffffffffffffffffffffffff1660048a01525173ffffffffffffffffffffffffffffffffffffffff1660248901525162ffffff1660448801525160020b60648701525173ffffffffffffffffffffffffffffffffffffffff16608486015251151560a48501525160c48401525173ffffffffffffffffffffffffffffffffffffffff1660e4830152610104820161012090528b6101248301528b8233815a9361014492602095f19081156122f0578c916122a8575b6fffffffffffffffffffffffffffffffff92501561228c57821561228157165b905b333b1561227d578a6040517fa58411940000000000000000000000000000000000000000000000000000000081528b6004820152818160248183335af180156106e757612268575b505080156122615783995b6120298b8230615c9c565b1561223f578a881561222d575b50505b156122265780945b801515908161220e575b506121e65785156121d957600492602092156121d257505b604051928380927f11da60b4000000000000000000000000000000000000000000000000000000008252335af180156121c757612198575b5086333b15610374576040517f0b0d9c0900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff92831660048201529185166024830152604482018390528160648183335af1801561218d57612174575b506108bd955060405194602086015260408501526040845261212c60608561568f565b612147575b50506040519182916020835260208301906155cb565b47908115159081612169575b50156121315761216291615b7c565b5f80612131565b90503014155f612153565b61217f87809261568f565b6121895785612109565b8580fd5b6040513d89823e3d90fd5b6020813d6020116121bf575b816121b16020938361568f565b81010312610149575161209b565b3d91506121a4565b6040513d8a823e3d90fd5b9050612063565b5050506004602088612063565b60048a7f7dd37f70000000000000000000000000000000000000000000000000000000008152fd5b9050821561221f5781115b5f61204b565b8510612219565b8294612041565b612238913390615da8565b5f8a612036565b8a881561224e575b5050612039565b61225a918b3391615bc7565b5f8a612247565b819961201e565b816122729161568f565b61227d578a5f612013565b8a80fd5b60801d8b0316611fc9565b821561229d5760801d165b90611fcb565b600f0b8b0316612297565b90506020823d6020116122e8575b816122c36020938361568f565b810103126122e4576fffffffffffffffffffffffffffffffff915190611fa9565b8b80fd5b3d91506122b6565b6040513d8e823e3d90fd5b73fffd8963efd1fc6a506488495d951d5263988d2594611e8f565b89840393611e80565b8d90611e1e565b8c8793611e15565b8780fd5b8680fd5b5060c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610374578061236a615458565b6064359060ff8216809203610a5c5773ffffffffffffffffffffffffffffffffffffffff1690813b15610a5c57829160e4839260405194859384927fd505accf00000000000000000000000000000000000000000000000000000000845233600485015230602485015260243560448501526044356064850152608484015260843560a484015260a43560c48401525af180156106e7576124085750f35b816124129161568f565b6103745780f35b5060807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103745760043567ffffffffffffffff811161037257366023820112156103725780600401359067ffffffffffffffff8211610910576024808201918360061b010136811161281f5760643567ffffffffffffffff811161281b576124a990369060040161555a565b6124b285615922565b916124c0604051938461568f565b8583527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06124ed87615922565b01875b8181106127f8575050865b8681036127b657506040519361251085615657565b61251987615922565b90612527604051928361568f565b8782528690602083015b81831061277e575050508452602084019360243585526040810160443581526e22d473030f116ddee9f6b43ac78ba33b1561277a5790889594939291604051957f4da3e5d90000000000000000000000000000000000000000000000000000000087526080600488015260e4870192519260606084890152835180915260206101048901940190895b81811061272a575050505160a48701525160c48601527ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc85820301602486015260208085519283815201940190865b8181106126e0575050506126518593859384933360448601527ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8584030160648601526156d0565b0381836e22d473030f116ddee9f6b43ac78ba35af180156106e7576126cb575b5050825b828103612680578380f35b806126976126926126c6938686615a5c565b615788565b60206126a4838787615a5c565b013560405191308852602052866040526060872090815c01905d604052615989565b612675565b816126d59161568f565b61091057825f612671565b9195965091929360206040826127196001948a516020809173ffffffffffffffffffffffffffffffffffffffff81511684520151910152565b019601910191899695949392612609565b9195969798995091929360206040826127666001948a516020809173ffffffffffffffffffffffffffffffffffffffff81511684520151910152565b0196019101918c99989796959493926125ba565b8880fd5b60408336031261227d57602060409182516127988161560e565b6127a18661552a565b81528286013583820152815201920191612531565b8060206127c76127f3938a8a615a5c565b0135604051906127d68261560e565b30825260208201526127e882876159c6565b5261138b81866159c6565b6124fb565b6020906040516128078161560e565b8a81528a83820152828288010152016124f0565b8480fd5b8380fd5b5060e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457612856615458565b61285e61554b565b6128666154e4565b9161286f615507565b60843560a4359460c43590814211612e675773ffffffffffffffffffffffffffffffffffffffff84811615939291908116158481612e4b575b612e2f575b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8a9314612e26575b73ffffffffffffffffffffffffffffffffffffffff6128f58784615e8a565b9590919015908115612e0b57735c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f925b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000006040519181602084019460601b16845260601b1660348201526028815261296160488261568f565b5190209015612de5577f96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f5b604051917fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060208401947fff00000000000000000000000000000000000000000000000000000000000000865260601b16602184015260358301526055820152605581526129fb60758261568f565b51902016936040517f0902f1ac000000000000000000000000000000000000000000000000000000008152606081600481895afa9081156122f0578c908d92612d89575b508515612d72576dffffffffffffffffffffffffffff80915b169116995f14612cd057907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff612a9f926103e86103e584809e030293849202020101615a25565b988015908115612cc5575b50156121e6578389915b612abf838584615c9c565b15612c51575b505050505f14612ba9578115612ba25786305b823b156103725760a473ffffffffffffffffffffffffffffffffffffffff918360405195869485937f022c0d9f0000000000000000000000000000000000000000000000000000000085528360048601528c6024860152166044840152608060648401528160848401525af1801561218d57612b8d575b509483916040965b15612b705750506116d091612b6b82615d03565b615b7c565b6060925086519382526020528086522082815c01905d83526116d0565b612b9887809261568f565b612189575f612b4f565b8684612ad8565b8115612c4a5786305b823b156103725760a473ffffffffffffffffffffffffffffffffffffffff918360405195869485937f022c0d9f0000000000000000000000000000000000000000000000000000000085528c6004860152836024860152166044840152608060648401528160848401525af1801561218d57612c35575b50948391604096612b57565b612c4087809261568f565b612189575f612c29565b8684612bb2565b612c5c838530615c9c565b15612c745750612c6b92615da8565b5f878382612ac5565b15612cba57612c839250615e2f565b3073ffffffffffffffffffffffffffffffffffffffff861603612ca6575b612c6b565b86341115612ca157612ca187340333615b7c565b612ca1923390615bc7565b90508911155f612aaa565b99989080612d5e57508115612d4f5734995b8a15612d2757906103e5612d03926103e8828e5b02910201918c0202615a25565b978015908115612d1c575b50156121e657838991612ab4565b90508810155f612d0e565b60048c7f7c7f7bb9000000000000000000000000000000000000000000000000000000008152fd5b612d5883615c6f565b99612ce2565b906103e5809b6103e8612d03949d8e612cf6565b906dffffffffffffffffffffffffffff8091612a58565b9150506060813d606011612ddd575b81612da56060938361568f565b810103126122e457612db681615a0a565b6040612dc460208401615a0a565b92015163ffffffff811603612dd9575f612a3f565b8c80fd5b3d9150612d98565b7fe18a34eb0e04b04f7a0ac29a6e80748dca96319b42c54d679cb821dca90c630361298c565b73c0aee478e3658e2610c5f7a4a2e1777ce9e4f2ac92612918565b600192506128d6565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc295506128ad565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc292506128a8565b6004887f203d82d8000000000000000000000000000000000000000000000000000000008152fd5b5060e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457612ec2615458565b9060243590612ecf6154e4565b90612ed8615507565b9160843593612ee56154c1565b9560c43567ffffffffffffffff811161281b57612f0690369060040161555a565b909773ffffffffffffffffffffffffffffffffffffffff871698891593845f14613109578631955b73ffffffffffffffffffffffffffffffffffffffff821661309e575b505073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000025fc36455aa30d012bbfb86f283975440d7ee8db1691823b1561232e5791612fc993918893604051958694859384937f1cff79cd000000000000000000000000000000000000000000000000000000008552600485016159da565b039134905af1801561186357908591613089575b50612ff1929115905061307a5782316158ae565b9380851061304657506020945073ffffffffffffffffffffffffffffffffffffffff163014613025575b5050604051908152f35b606090604051923082528552806040522082815c01905d6040525f8061301b565b8260649186887f20768e08000000000000000000000000000000000000000000000000000000008452600452602452604452fd5b6130848386615e01565b6158ae565b816130939161568f565b61281f57835f612fdd565b8381156130b7576130b0923390615bc7565b5f80612f4a565b50506130c281615c6f565b9083600183116130d5575b5050506130b0565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff613101930191615da8565b5f80836130cd565b613113878a615e01565b95612f2e565b5060207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103745761314c615458565b6fa1903eab0000000000000000000000008252602082602460103473ae7ab96520de3a18e5e111b5eaab095312d7fe845af115610372578151906f8fcb4e5b0000000000000000000000008352601452806034528138604460108373ae7ab96520de3a18e5e111b5eaab095312d7fe845af11561037257602091603452604051908152f35b5060607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457613204615458565b61320c61554b565b6132146154e4565b9073ffffffffffffffffffffffffffffffffffffffff8454163303610c88571561329d5773ffffffffffffffffffffffffffffffffffffffff6044602092858360405196879586947f558a729700000000000000000000000000000000000000000000000000000000865216600485015260016024850152165af180156106e7576106bf575080f35b61049091615d2e565b5060e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610374576132d9615458565b6024356132e46154e4565b9060643567ffffffffffffffff811161281b5761330590369060040161559a565b60843567ffffffffffffffff81116123325761332590369060040161559a565b9561332e6154c1565b60c43567ffffffffffffffff81116136c257906133518a9392369060040161555a565b909261335c8761593a565b98855b8b898b818403613651575050505073ffffffffffffffffffffffffffffffffffffffff82166135e6575b505073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000025fc36455aa30d012bbfb86f283975440d7ee8db16803b1561281b57613405938593604051958694859384937f1cff79cd000000000000000000000000000000000000000000000000000000008552600485016159da565b039134905af180156106e7576135d1575b50506134248295949561593a565b9573ffffffffffffffffffffffffffffffffffffffff8516301495885b84810361348e57888a604051918291602083016020845282518091526020604085019301915b818110613475575050500390f35b8251845285945060209384019390920191600101613467565b73ffffffffffffffffffffffffffffffffffffffff6134b161269283888a6159b6565b166135b2576134cd87315b6134c683856159c6565b51906158ae565b6134d7828b6159c6565b526134e2818a6159c6565b516134ee8285876159b6565b351161354157613502908861350757615989565b613441565b61351561269282888a6159b6565b61351f828c6159c6565b51604051918d3090526020528c60405260608d2090815c01905d604052615989565b89939150613581818a9461357a8261357461269273ffffffffffffffffffffffffffffffffffffffff9760649c8e6159b6565b976159c6565b51946159b6565b35927f20768e0800000000000000000000000000000000000000000000000000000000855216600452602452604452fd5b6134cd6135cc886135c7612692858a8c6159b6565b615e01565b6134bc565b816135db9161568f565b61233257865f613416565b8381156135ff576135f8923390615bc7565b5f80613389565b505061360a81615c6f565b90836001831161361d575b5050506135f8565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff613649930191615da8565b5f8083613615565b90816136a095969798999a73ffffffffffffffffffffffffffffffffffffffff61368161269288868199986159b6565b16151590506136ac5750509050315b61369a828d6159c6565b52615989565b908c959493929161335f565b6136bd936135c792612692926159b6565b613690565b8980fd5b5060607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103745760043567ffffffffffffffff81116103725761371190369060040161555a565b60206137a561371e6154e4565b9260405183810190602435825273ffffffffffffffffffffffffffffffffffffffff861660408201526040815261375660608261568f565b5190209447916137668330615cd9565b50604051968794859384937fea9384fa0000000000000000000000000000000000000000000000000000000085526040600486015260448501916156d0565b90602483015203916e696760e15f265e828db644a0c242eb5af191821561104b578392613878575b50826e696760e15f265e828db644a0c242eb3b15610374576040517f23b872dd00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff9290921660248301526044820183905281606481836e696760e15f265e828db644a0c242eb5af1801561104b57613863575b602082604051908152f35b61386e83809261568f565b6103725781613858565b9091506020813d6020116138a4575b816138946020938361568f565b810103126101495751905f6137cd565b3d9150613887565b5060a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610374578060443560ff8116809103610a5757736b175474e89094c44da98b954eedeac495271d0f3b15610a5757604051907f8fcbaf0c000000000000000000000000000000000000000000000000000000008252336004830152306024830152600435604483015260243560648301526001608483015260a482015260643560c482015260843560e482015281816101048183736b175474e89094c44da98b954eedeac495271d0f5af180156106e7576124085750f35b506101207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610374576139bf615458565b6139c761554b565b6139cf615588565b606435908160020b80920361281b576139e661549e565b926139ef6154c1565b9360c43592610104354211612e675787939215929190838381613c18575b50613ba8575b90613ad29562ffffff73ffffffffffffffffffffffffffffffffffffffff9360405196336020890152858c16604089015215606088015216608086015260a08501521660c083015273ffffffffffffffffffffffffffffffffffffffff851660e083015261010082015260e4356101208201526101208152613a976101408261568f565b604051809381927f48c894910000000000000000000000000000000000000000000000000000000083526020600484015260248301906155cb565b0381836e04444c5dc75cb358380d2e3de08a905af1908115611826578491613b30575b5060408180518101031261281f5760606040948560208401519301519386519582526020528086522082815c01905d82845282526020820152f35b9050833d8082843e613b42818461568f565b8201916020818403126103725780519067ffffffffffffffff8211610910570182601f82011215610372578051613b78816158e8565b93613b86604051958661568f565b81855260208284010111610910578060208093018386015e830101525f613af5565b9390929491505073ffffffffffffffffffffffffffffffffffffffff8216155f14613c095734925b8315613be157918793919492613a13565b6004887f7c7f7bb9000000000000000000000000000000000000000000000000000000008152fd5b613c1282615c6f565b92613bd0565b9050155f613a0d565b50346103745760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457613c59615458565b50613c6261547b565b5060643567ffffffffffffffff811161037257613c8390369060040161555a565b505060206040517f150b7a02000000000000000000000000000000000000000000000000000000008152f35b506105207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457613ce3615458565b90613cec61554b565b91366101a41161037257366104241161037257366104c411610372576104c435926104e43591610504354211614fb557613d24615765565b91849182805b60058110614f63575b5073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8514851517938897845f14614ed75760018201805b6148245750871515888a8261481a575b50506147f2575b85156147ec5773c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2965b613d9d8a8930615c9c565b1561479d575b918992823060601b915b8382111561400a57505050508415998a5f14613ff45782988015159081613fea575b50613fc25760409a5b15613f065750821573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee84141715613eba5750613e09915082615b7c565b81613e99575b50613e23575b505082519182526020820152f35b15613e7157504780613e61575b50613e39615c2e565b80613e48575b505b5f80613e15565b80613e55613e5b92615d03565b33615b7c565b5f613e3f565b613e6b9033615b7c565b5f613e30565b613e7a81615c6f565b80613e87575b5050613e41565b613e92913390615da8565b5f80613e80565b73ffffffffffffffffffffffffffffffffffffffff1630141590505f613e0f565b8373ffffffffffffffffffffffffffffffffffffffff81163003613ef657506060908a5193858252602052808b522090815c01905d8752613e09565b9050613f0192615da8565b613e09565b909181613f12916158ae565b91831573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee85141715613f5b5750613f3f91925083615b7c565b80613f4b575b50613e09565b613f559033615b7c565b5f613f45565b9073ffffffffffffffffffffffffffffffffffffffff85163003613fb15760608b519286815285602052808d522090815c01905d89525b80613f9f575b5050613e09565b613faa913390615da8565b5f80613f98565b613fbd91508484615da8565b613f92565b6004827f7dd37f70000000000000000000000000000000000000000000000000000000008152fd5b905083105f613dcf565b80919a985082106121e657988960409a98613dd8565b61401b612692600184811b01615726565b61402d6126926001850160011b615726565b9661403f61403a856157a9565b6157bc565b60408101516060820151946008821461466f57801573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8214171561466a575073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25b846040518160405289602c526fdd62ed3e000000000000000000000000600c526020806044601c865afa601f3d111660205102906040521561465a575b5050891573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8b141793841561464b5747955b8a6001840361427a575073ffffffffffffffffffffffffffffffffffffffff9250600a036141f657169060208151600f0b910151600f0b90823b156136c2576040517f3df02124000000000000000000000000000000000000000000000000000000008152600f91820b600482015291900b602482015260448101929092525f606483015287908290608490829084905af1801561218d579087916141e1575b50505b156141d357475b818111156141ab570394906001905b0190613dad565b6004867f7c7f7bb9000000000000000000000000000000000000000000000000000000008152fd5b6141dc86615c6f565b614195565b816141eb9161568f565b61218957855f61418b565b16906020815191015191803b156136c2578992918360849260405196879586947f5b41b9080000000000000000000000000000000000000000000000000000000086526004860152602485015260448401528160648401525af1801561218d57908791614265575b505061418e565b8161426f9161568f565b61218957855f61425e565b91926002810361431a5750505073ffffffffffffffffffffffffffffffffffffffff169060208151600f0b910151600f0b90823b156136c2576040517fa6417ed6000000000000000000000000000000000000000000000000000000008152600f91820b600482015291900b602482015260448101929092525f606483015287908290608490829084905af1801561218d5790879161426557505061418e565b9294939192600481036145565750600a81036143f157506040516020936143a8936101249361435c9161010090614351828761568f565b503685375183615876565b528a73ffffffffffffffffffffffffffffffffffffffff60405196879586947f52d7f3170000000000000000000000000000000000000000000000000000000086526004860190615887565b82610104850152165af1801561218d576143c3575b5061418e565b6143e39060203d81116143ea575b6143db818361568f565b810190615808565b505f6143bd565b503d6143d1565b90919060148103614497575060648160209394614473935061442860409687519361441c898661568f565b5087368537518361583e565b528b73ffffffffffffffffffffffffffffffffffffffff865197889586947f0b4c7e4d000000000000000000000000000000000000000000000000000000008652600486019061584f565b826044850152165af190811561448e57506143c3575061418e565b513d89823e3d90fd5b601e1415905061452e576084896020936144c9614515946060604051946144be828761568f565b5036853751836157f7565b528a73ffffffffffffffffffffffffffffffffffffffff60405196879586947f4515cef30000000000000000000000000000000000000000000000000000000086526004860190615817565b826064850152165af1801561218d576143c3575061418e565b6004897f7c7f7bb9000000000000000000000000000000000000000000000000000000008152fd5b9194925090600603611c075760209173ffffffffffffffffffffffffffffffffffffffff91600a036145e85716920151600f0b90823b1561277a5790606489928360405195869485937f1a4d01d2000000000000000000000000000000000000000000000000000000008552600485015260248401528160448401525af1801561218d5790879161426557505061418e565b1692015190823b1561277a5790606489928360405195869485937ff1dc3cc9000000000000000000000000000000000000000000000000000000008552600485015260248401528160448401525af1801561218d5790879161426557505061418e565b6146548b615c6f565b956140eb565b61466391615d2e565b5f846140c5565b614088565b9350505096915073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81148115178061476a575b156146fd575050806146c0575b600173c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2916141a4565b8447106146d5576146d085615a9b565b6146a3565b6004847f7c7f7bb9000000000000000000000000000000000000000000000000000000008152fd5b73ffffffffffffffffffffffffffffffffffffffff1673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2149081614748575b50156146d55761473f85615d03565b600184916141a4565b905073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81149015175f614730565b5073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff831614614696565b86156147e0578934106147b8576147b38a615a9b565b613da3565b6004827f85cf0a35000000000000000000000000000000000000000000000000000000008152fd5b6147b38a30338b615bc7565b86613d92565b807f7dd37f700000000000000000000000000000000000000000000000000000000060049252fd5b119050885f613d6e565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01614857612692600183811b01615726565b61486361403a836157a9565b604081015160608201519060088103614881575b5050505080613d5e565b939c93600181036149fa5750600a0361494b5780516020918201516040517f67df02ca000000000000000000000000000000000000000000000000000000008152600f92830b6004820152910b60248201526044810193909352908290606490829073ffffffffffffffffffffffffffffffffffffffff165afa9081156106e757908a918391614917575b50995b5f8080614877565b9150506020813d8211614943575b816149326020938361568f565b81010312610149578990515f61490c565b3d9150614925565b80516020918201516040517f37ed3a7a000000000000000000000000000000000000000000000000000000008152600481019290925260248201526044810193909352908290606490829073ffffffffffffffffffffffffffffffffffffffff165afa9081156106e757908a9183916149c6575b509961490f565b9150506020813d82116149f2575b816149e16020938361568f565b81010312610149578990515f6149bf565b3d91506149d4565b9193929160028103614ba157505060208351600f0b930151600f0b9084841380614b98575b15614b1d575060058c1015614af0576020917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8092614ad58f614a7d73ffffffffffffffffffffffffffffffffffffffff9160051b61042401615788565b1693604051978896879586957f67df02ca00000000000000000000000000000000000000000000000000000000875201600f0b9101600f0b600485016040919493926060820195600f0b8252600f0b60208201520152565b03915afa9081156106e757908a9183916149c657509961490f565b6024847f4e487b710000000000000000000000000000000000000000000000000000000081526032600452fd5b6040517f0e71d1b9000000000000000000000000000000000000000000000000000000008152600f94850b60048201529190930b60248201526044810191909152906020908290606490829073ffffffffffffffffffffffffffffffffffffffff165afa9081156106e757908a9183916149c657509961490f565b50848213614a1f565b9293919260048103614cc357506020929391600a604492145f14614c295751600f0b9173ffffffffffffffffffffffffffffffffffffffff60405195869485937fcc2b27d700000000000000000000000000000000000000000000000000000000855260048501526024840152165afa9081156106e757908a9183916149c657505b9961490f565b519173ffffffffffffffffffffffffffffffffffffffff60405195869485937f4fb08c5e00000000000000000000000000000000000000000000000000000000855260048501526024840152165afa9081156106e757908a918391614c8f575b50614c23565b9150506020813d8211614cbb575b81614caa6020938361568f565b81010312610149578990515f614c89565b3d9150614c9d565b600603614eaf57600a8103614d6b5750610124614d4a9160209394614cff856101009360405194614cf4818761568f565b368637015183615876565b5273ffffffffffffffffffffffffffffffffffffffff60405195869485937f2f0149080000000000000000000000000000000000000000000000000000000085526004850190615887565b87610104840152165afa9081156106e757908a9183916149c657509961490f565b60148103614e105750614de66064602092604095614d9c85885193614d908a8661568f565b8936863701518361583e565b5273ffffffffffffffffffffffffffffffffffffffff865195869485937fed8e84f3000000000000000000000000000000000000000000000000000000008552600485019061584f565b886044840152165afa918215614e075750908a9183916149c657509961490f565b513d84823e3d90fd5b91929091601e036146d5576084602092614e8f92614e448560609360405194614e39818761568f565b3686370151836157f7565b5273ffffffffffffffffffffffffffffffffffffffff60405195869485937f3883e1190000000000000000000000000000000000000000000000000000000085526004850190615817565b876064840152165afa9081156106e757908a9183916149c657509961490f565b6004857f7c7f7bb9000000000000000000000000000000000000000000000000000000008152fd5b975088614f23578415614f145734975b88613d7557807f7c7f7bb90000000000000000000000000000000000000000000000000000000060049252fd5b614f1d86615c6f565b97614ee7565b88978580614f59575b15613d7557807f85cf0a350000000000000000000000000000000000000000000000000000000060049252fd5b5089341415614f2c565b939073ffffffffffffffffffffffffffffffffffffffff614f8b612692600188811b01615726565b1615614fae575050614fa56126926001850160011b615726565b60018401613d2a565b9093613d33565b6004847f203d82d8000000000000000000000000000000000000000000000000000000008152fd5b5060607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457615010615458565b34159060443560243583156150fb575b73ffffffffffffffffffffffffffffffffffffffff83169384151590816150f3575b50615054575b61049093503092615ae3565b8061506f57610490935061506a82303386615bc7565b615048565b6040517ffe99049a0000000000000000000000000000000000000000000000000000000081523360048201523060248201526044810182905260648101839052936020908590608490829089905af193841561186357610490946150d4575b50615048565b6150ec9060203d6020116106e0576106d8818361568f565b505f6150ce565b90505f615042565b806151aa5773ffffffffffffffffffffffffffffffffffffffff831673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2810361517057508134036151485761514382615afe565b615020565b6004857f85cf0a35000000000000000000000000000000000000000000000000000000008152fd5b6151a457815b3414615020576004857f85cf0a35000000000000000000000000000000000000000000000000000000008152fd5b84615176565b6004857fdfa1a408000000000000000000000000000000000000000000000000000000008152fd5b5060a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261014957615205615458565b6024359060843567ffffffffffffffff81116101495761522990369060040161555a565b604051916152368361560e565b73ffffffffffffffffffffffffffffffffffffffff841683528460208401526040519261526284615657565b83526020830192604435845260408101916064358352604051906152858261560e565b3082528760208301526e22d473030f116ddee9f6b43ac78ba33b15610149575f9461533b6153549361530796604051998a9889987f30f28b7a000000000000000000000000000000000000000000000000000000008a5260048a0190516020809173ffffffffffffffffffffffffffffffffffffffff81511684520151910152565b516044880152516064870152805173ffffffffffffffffffffffffffffffffffffffff1660848701526020015160a4860152565b3360c485015261010060e48501526101048401916156d0565b0381836e22d473030f116ddee9f6b43ac78ba35af180156153a15761538c575b50308352602052816040526060822090815c01905d80f35b6153999193505f9061568f565b5f915f615374565b6040513d5f823e3d90fd5b60407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610149576153de615458565b6153e661554b565b9073ffffffffffffffffffffffffffffffffffffffff5f541633036100f05773ffffffffffffffffffffffffffffffffffffffff165f52600160205260405f209060ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00835416911515161790555f80f35b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361014957565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361014957565b6084359073ffffffffffffffffffffffffffffffffffffffff8216820361014957565b60a4359073ffffffffffffffffffffffffffffffffffffffff8216820361014957565b6044359073ffffffffffffffffffffffffffffffffffffffff8216820361014957565b6064359073ffffffffffffffffffffffffffffffffffffffff8216820361014957565b359073ffffffffffffffffffffffffffffffffffffffff8216820361014957565b60243590811515820361014957565b9181601f840112156101495782359167ffffffffffffffff8311610149576020838186019501011161014957565b6044359062ffffff8216820361014957565b9181601f840112156101495782359167ffffffffffffffff8311610149576020808501948460051b01011161014957565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602080948051918291828752018686015e5f8582860101520116010190565b6040810190811067ffffffffffffffff82111761562a57604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6060810190811067ffffffffffffffff82111761562a57604052565b60a0810190811067ffffffffffffffff82111761562a57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761562a57604052565b601f82602094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe093818652868601375f8582860101520116010190565b90816020910312610149575180151581036101495790565b600b8110156157385760051b60440190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b60443573ffffffffffffffffffffffffffffffffffffffff811681036101495790565b3573ffffffffffffffffffffffffffffffffffffffff811681036101495790565b60058110156157385760071b6101a40190565b604051906157cb60808361568f565b81608082019136831161014957905b8282106157e75750505090565b81358152602091820191016157da565b9060038110156157385760051b0190565b90816020910312610149575190565b905f905b6003821061582857505050565b602080600192855181520193019101909161581b565b9060028110156157385760051b0190565b905f905b6002821061586057505050565b6020806001928551815201930191019091615853565b9060088110156157385760051b0190565b905f905b6008821061589857505050565b602080600192855181520193019101909161588b565b919082039182116158bb57565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b67ffffffffffffffff811161562a57601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b67ffffffffffffffff811161562a5760051b60200190565b9061594482615922565b615951604051918261568f565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061597f8294615922565b0190602036910137565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146158bb5760010190565b91908110156157385760051b0190565b80518210156157385760209160051b010190565b60409073ffffffffffffffffffffffffffffffffffffffff615a07959316815281602082015201916156d0565b90565b51906dffffffffffffffffffffffffffff8216820361014957565b8115615a2f570490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b91908110156157385760061b0190565b3d15615a96573d90615a7d826158e8565b91615a8b604051938461568f565b82523d5f602084013e565b606090565b80615ade5750475b615aac81615afe565b60405190305f5273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26020525f60405260605f2090815c01905d604052565b615aa3565b604051935f5260205260405260605f2090815c01905d604052565b3073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc214615b4a575f908180389273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25af115615b3d57565b63b12d13eb5f526004601cfd5b6040519073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25f525f6020525f60405260605f2090815c01905d604052565b903073ffffffffffffffffffffffffffffffffffffffff831614615baa57905f80809338935af115615b3d57565b604051915f525f6020525f60405260605f2090815c01905d604052565b916040519360605260405260601b602c526f23b872dd000000000000000000000000600c5260205f6064601c82855af1908160015f51141615615c10575b50505f606052604052565b3b153d171015615c21575f80615c05565b637939f4245f526004601cfd5b306014526f70a082310000000000000000000000005f526020806024601073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25afa601f3d11166020510290565b6020602460108293306014526f70a082310000000000000000000000005f525afa601f3d11166020510290565b9092915f93604051925f526020525f60405260605f2090815c81811015615cc6575b505050604052565b909192945003905d6001915f8080615cbe565b9190915f92604051915f525f6020525f60405260605f2090815c81811015615cc657505050604052565b632e1a7d4d5f526020525f386024601c8373c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25af150565b906014527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6034526f095ea7b30000000000000000000000005f5260205f6044601082855af1908160015f51141615615d8a575b50505f603452565b3b153d171015615d9b575f80615d82565b633e3f8f735f526004601cfd5b91906014526034526fa9059cbb0000000000000000000000005f5260205f6044601082855af1908160015f51141615615de35750505f603452565b3b153d171015615df4575f80615d82565b6390b8ec185f526004601cfd5b602460106020939284936014526f70a082310000000000000000000000005f525afa601f3d11166020510290565b5f3881808573c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25af1506014526034526fa9059cbb0000000000000000000000005f525f38604460108373c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25af1505f603452565b73ffffffffffffffffffffffffffffffffffffffff821673ffffffffffffffffffffffffffffffffffffffff82161090815f14615ec45792565b9192565b606091615ed491615e8a565b9390604051928352602083015260408201522060ff5f537fe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b546035527f1f98431c8ad98523631ae4a59f267346ea31f98400000000000000000000000060015260155260555f205f6035529156fea2646970667358221220680d3856dd5dd9a45a7a5d84fcf6d844dbc78e980b32ee2b70e49457f3162b8964736f6c63430008210033

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

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