ETH Price: $3,079.33 (-1.34%)

Contract

0x7966aF62034313D87Ede39380bf60f1A84c62BE7
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Execute206419432024-08-30 14:18:5979 days ago1725027539IN
0x7966aF62...A84c62BE7
0 ETH0.000913015.4288886
Execute204650372024-08-05 21:25:47104 days ago1722893147IN
0x7966aF62...A84c62BE7
0 ETH0.000986355.86371821
Execute203344532024-07-18 15:58:47122 days ago1721318327IN
0x7966aF62...A84c62BE7
0 ETH0.002742716.30716703
Execute202857602024-07-11 20:49:23129 days ago1720730963IN
0x7966aF62...A84c62BE7
0 ETH0.001042326.19686468
Execute202733402024-07-10 3:14:35131 days ago1720581275IN
0x7966aF62...A84c62BE7
0 ETH0.000883615.25405945
Execute201914052024-06-28 16:33:47142 days ago1719592427IN
0x7966aF62...A84c62BE7
0 ETH0.001549968.43258929
Execute200849402024-06-13 19:19:35157 days ago1718306375IN
0x7966aF62...A84c62BE7
0 ETH0.0017437210.36685346
Execute200217122024-06-04 23:22:11166 days ago1717543331IN
0x7966aF62...A84c62BE7
0 ETH0.001377096.67854896
Execute200216992024-06-04 23:19:35166 days ago1717543175IN
0x7966aF62...A84c62BE7
0 ETH0.001587756.6361771
Execute199936442024-06-01 1:19:59170 days ago1717204799IN
0x7966aF62...A84c62BE7
0.00418638 ETH0.0011085.41550436
Execute199921562024-05-31 20:19:59170 days ago1717186799IN
0x7966aF62...A84c62BE7
0.00528954 ETH0.001292628.76758079
Execute198851432024-05-16 21:12:47185 days ago1715893967IN
0x7966aF62...A84c62BE7
0 ETH0.0006914.20025989
Execute197835632024-05-02 16:14:47199 days ago1714666487IN
0x7966aF62...A84c62BE7
0 ETH0.0070689517.06392114
Execute197717822024-05-01 0:44:47201 days ago1714524287IN
0x7966aF62...A84c62BE7
0.00669678 ETH0.003821346.43888515
Execute197694342024-04-30 16:51:35201 days ago1714495895IN
0x7966aF62...A84c62BE7
0.00335117 ETH0.0060172416.79505329
Execute197646872024-04-30 0:57:47202 days ago1714438667IN
0x7966aF62...A84c62BE7
0.965 ETH0.003916656.97668365
Execute197410222024-04-26 17:30:11205 days ago1714152611IN
0x7966aF62...A84c62BE7
0 ETH0.001032365.57398064
Execute197403802024-04-26 15:20:23205 days ago1714144823IN
0x7966aF62...A84c62BE7
0 ETH0.003139949.33539228
Execute197369902024-04-26 3:55:23206 days ago1714103723IN
0x7966aF62...A84c62BE7
0 ETH0.001179415.54769173
Execute197364772024-04-26 2:12:11206 days ago1714097531IN
0x7966aF62...A84c62BE7
0 ETH0.001175496.84412915
Execute197360962024-04-26 0:55:35206 days ago1714092935IN
0x7966aF62...A84c62BE7
0 ETH0.001321288.52016336
Execute197357682024-04-25 23:49:23206 days ago1714088963IN
0x7966aF62...A84c62BE7
0 ETH0.001092245.8283697
Execute197357642024-04-25 23:48:35206 days ago1714088915IN
0x7966aF62...A84c62BE7
0 ETH0.000505937.98695091
Execute197356572024-04-25 23:26:35206 days ago1714087595IN
0x7966aF62...A84c62BE7
0 ETH0.000492337.7736796
Execute197355812024-04-25 23:11:23206 days ago1714086683IN
0x7966aF62...A84c62BE7
0 ETH0.002530446.23533168
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To
199936442024-06-01 1:19:59170 days ago1717204799
0x7966aF62...A84c62BE7
0.00418638 ETH
199921562024-05-31 20:19:59170 days ago1717186799
0x7966aF62...A84c62BE7
0.00528954 ETH
197717822024-05-01 0:44:47201 days ago1714524287
0x7966aF62...A84c62BE7
0.00688606 ETH
197717822024-05-01 0:44:47201 days ago1714524287
0x7966aF62...A84c62BE7
0.00688606 ETH
197717822024-05-01 0:44:47201 days ago1714524287
0x7966aF62...A84c62BE7
0.00669678 ETH
197694342024-04-30 16:51:35201 days ago1714495895
0x7966aF62...A84c62BE7
0.00335117 ETH
197646872024-04-30 0:57:47202 days ago1714438667
0x7966aF62...A84c62BE7
0.965 ETH
197410222024-04-26 17:30:11205 days ago1714152611
0x7966aF62...A84c62BE7
0.001 ETH
197410222024-04-26 17:30:11205 days ago1714152611
0x7966aF62...A84c62BE7
0.001 ETH
197403802024-04-26 15:20:23205 days ago1714144823
0x7966aF62...A84c62BE7
0.01008564 ETH
197403802024-04-26 15:20:23205 days ago1714144823
0x7966aF62...A84c62BE7
0.01008564 ETH
197369902024-04-26 3:55:23206 days ago1714103723
0x7966aF62...A84c62BE7
0.001 ETH
197369902024-04-26 3:55:23206 days ago1714103723
0x7966aF62...A84c62BE7
0.001 ETH
197350092024-04-25 21:16:47206 days ago1714079807
0x7966aF62...A84c62BE7
0.04 ETH
197349272024-04-25 21:00:23206 days ago1714078823
0x7966aF62...A84c62BE7
0.1056621 ETH
197349272024-04-25 21:00:23206 days ago1714078823
0x7966aF62...A84c62BE7
0.1056621 ETH
197286472024-04-24 23:56:35207 days ago1714002995
0x7966aF62...A84c62BE7
0.03188601 ETH
197286472024-04-24 23:56:35207 days ago1714002995
0x7966aF62...A84c62BE7
0.03188601 ETH
197286062024-04-24 23:48:23207 days ago1714002503
0x7966aF62...A84c62BE7
0.13697313 ETH
197286062024-04-24 23:48:23207 days ago1714002503
0x7966aF62...A84c62BE7
0.13697313 ETH
197285412024-04-24 23:35:23207 days ago1714001723
0x7966aF62...A84c62BE7
0.01758994 ETH
197285412024-04-24 23:35:23207 days ago1714001723
0x7966aF62...A84c62BE7
0.01758994 ETH
197272542024-04-24 19:16:23207 days ago1713986183
0x7966aF62...A84c62BE7
0.13758994 ETH
197272542024-04-24 19:16:23207 days ago1713986183
0x7966aF62...A84c62BE7
0.13758994 ETH
197272472024-04-24 19:14:59207 days ago1713986099
0x7966aF62...A84c62BE7
0.13758994 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Settler

Compiler Version
v0.8.25+commit.b61c2a91

Optimization Enabled:
Yes with 1000000 runs

Other Settings:
cancun EvmVersion
File 1 of 24 : Settler.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

import {IERC20, IERC20Meta} from "./IERC20.sol";
import {ISignatureTransfer} from "permit2/src/interfaces/ISignatureTransfer.sol";

import {Permit2Payment} from "./core/Permit2Payment.sol";
import {Basic} from "./core/Basic.sol";
import {OtcOrderSettlement} from "./core/OtcOrderSettlement.sol";
import {UniswapV3} from "./core/UniswapV3.sol";
import {UniswapV2} from "./core/UniswapV2.sol";
import {IPSM, MakerPSM} from "./core/MakerPSM.sol";

import {SafeTransferLib} from "./vendor/SafeTransferLib.sol";
import {UnsafeMath} from "./utils/UnsafeMath.sol";
import {FullMath} from "./vendor/FullMath.sol";
import {FreeMemory} from "./utils/FreeMemory.sol";

import {ISettlerActions} from "./ISettlerActions.sol";
import {TooMuchSlippage} from "./core/SettlerErrors.sol";

/// @dev This library omits index bounds/overflow checking when accessing calldata arrays for gas efficiency, but still includes checks against `calldatasize()` for safety.
library CalldataDecoder {
    function decodeCall(bytes[] calldata data, uint256 i)
        internal
        pure
        returns (bytes4 selector, bytes calldata args)
    {
        assembly ("memory-safe") {
            // helper functions
            function panic(code) {
                mstore(0x00, 0x4e487b71) // keccak256("Panic(uint256)")[:4]
                mstore(0x20, code)
                revert(0x1c, 0x24)
            }
            function overflow() {
                panic(0x11) // 0x11 -> arithmetic under-/over- flow
            }
            function bad_calldata() {
                revert(0x00, 0x00) // empty reason for malformed calldata
            }

            // initially, we set `args.offset` to the pointer to the length. this is 32 bytes before the actual start of data
            args.offset :=
                add(
                    data.offset,
                    calldataload(
                        add(shl(5, i), data.offset) // can't overflow; we assume `i` is in-bounds
                    )
                )
            // because the offset to `args` stored in `data` is arbitrary, we have to check it
            if lt(args.offset, add(shl(5, data.length), data.offset)) { overflow() }
            if iszero(lt(args.offset, calldatasize())) { bad_calldata() }
            // now we load `args.length` and set `args.offset` to the start of data
            args.length := calldataload(args.offset)
            args.offset := add(args.offset, 0x20) // can't overflow; calldata can't be that long
            {
                // check that the end of `args` is in-bounds
                let end := add(args.offset, args.length)
                if lt(end, args.offset) { overflow() }
                if gt(end, calldatasize()) { bad_calldata() }
            }
            // slice off the first 4 bytes of `args` as the selector
            if lt(args.length, 4) {
                // loading selector results in out-of-bounds read
                panic(0x32) // 0x32 -> out-of-bounds array access
            }
            selector := calldataload(args.offset) // solidity cleans dirty bits automatically
            args.length := sub(args.length, 4) // can't underflow; checked above
            args.offset := add(args.offset, 4) // can't overflow/oob; we already checked `end`
        }
    }
}

/// @custom:security-contact [email protected]
contract Settler is Permit2Payment, Basic, OtcOrderSettlement, UniswapV3, UniswapV2, MakerPSM, FreeMemory {
    using SafeTransferLib for IERC20;
    using SafeTransferLib for address payable;
    using UnsafeMath for uint256;
    using FullMath for uint256;
    using CalldataDecoder for bytes[];

    error ActionInvalid(uint256 i, bytes4 action, bytes data);

    receive() external payable {}

    // When you change this, you must make corresponding changes to
    // `sh/deploy_new_chain.sh` to set `constructor_args`.
    constructor(address uniFactory, bytes32 poolInitCodeHash, address dai)
        Permit2Payment()
        Basic()
        OtcOrderSettlement()
        UniswapV3(uniFactory, poolInitCodeHash)
        UniswapV2()
        MakerPSM(dai)
    {}

    struct AllowedSlippage {
        address buyToken;
        address recipient;
        uint256 minAmountOut;
    }

    function _checkSlippageAndTransfer(AllowedSlippage calldata slippage) internal {
        // This final slippage check effectively prohibits custody optimization on the
        // final hop of every swap. This is gas-inefficient. This is on purpose. Because
        // ISettlerActions.BASIC_SELL could interact with an intents-based settlement
        // mechanism, we must ensure that the user's want token increase is coming
        // directly from us instead of from some other form of exchange of value.
        (address buyToken, address recipient, uint256 minAmountOut) =
            (slippage.buyToken, slippage.recipient, slippage.minAmountOut);
        if (minAmountOut != 0 || buyToken != address(0)) {
            if (buyToken == ETH_ADDRESS) {
                uint256 amountOut = address(this).balance;
                if (amountOut < minAmountOut) {
                    revert TooMuchSlippage(buyToken, minAmountOut, amountOut);
                }
                payable(recipient).safeTransferETH(amountOut);
            } else {
                uint256 amountOut = IERC20(buyToken).balanceOf(address(this));
                if (amountOut < minAmountOut) {
                    revert TooMuchSlippage(buyToken, minAmountOut, amountOut);
                }
                IERC20(buyToken).safeTransfer(recipient, amountOut);
            }
        }
    }

    function _otcVIP(bytes calldata data) internal DANGEROUS_freeMemory {
        (
            address recipient,
            ISignatureTransfer.PermitTransferFrom memory makerPermit,
            address maker,
            bytes memory makerSig,
            ISignatureTransfer.PermitTransferFrom memory takerPermit,
            bytes memory takerSig
        ) = abi.decode(
            data,
            (
                address,
                ISignatureTransfer.PermitTransferFrom,
                address,
                bytes,
                ISignatureTransfer.PermitTransferFrom,
                bytes
            )
        );

        fillOtcOrder(recipient, makerPermit, maker, makerSig, takerPermit, takerSig);
    }

    function _uniV3VIP(bytes calldata data) internal DANGEROUS_freeMemory {
        (
            address recipient,
            uint256 amountIn,
            uint256 amountOutMin,
            bytes memory path,
            ISignatureTransfer.PermitTransferFrom memory permit,
            bytes memory sig
        ) = abi.decode(data, (address, uint256, uint256, bytes, ISignatureTransfer.PermitTransferFrom, bytes));

        sellTokenForTokenToUniswapV3VIP(recipient, path, amountIn, amountOutMin, permit, sig);
    }

    function execute(bytes[] calldata actions, AllowedSlippage calldata slippage) public payable {
        if (actions.length != 0) {
            (bytes4 action, bytes calldata data) = actions.decodeCall(0);
            if (action == ISettlerActions.SETTLER_OTC_PERMIT2.selector) {
                _otcVIP(data);
            } else if (action == ISettlerActions.UNISWAPV3_PERMIT2_SWAP_EXACT_IN.selector) {
                _uniV3VIP(data);
            } else {
                _dispatch(0, action, data, _msgSender());
            }
        }

        for (uint256 i = 1; i < actions.length; i = i.unsafeInc()) {
            (bytes4 action, bytes calldata data) = actions.decodeCall(i);
            _dispatch(i, action, data, _msgSender());
        }

        _checkSlippageAndTransfer(slippage);
    }

    function _hashArrayOfBytes(bytes[] calldata actions) internal pure returns (bytes32 result) {
        // This function deliberately does no bounds checking on `actions` for
        // gas efficiency. We assume that `actions` will get used elsewhere in
        // this context and any OOB or other malformed calldata will result in a
        // revert later.
        assembly ("memory-safe") {
            let ptr := mload(0x40)
            let hashesLength := shl(5, actions.length)
            for {
                let i := actions.offset
                let dst := ptr
                let end := add(i, hashesLength)
            } lt(i, end) {
                i := add(i, 0x20)
                dst := add(dst, 0x20)
            } {
                let src := add(actions.offset, calldataload(i))
                let length := calldataload(src)
                calldatacopy(dst, add(src, 0x20), length)
                mstore(dst, keccak256(dst, length))
            }
            result := keccak256(ptr, hashesLength)
        }
    }

    function _hashActionsAndSlippage(bytes[] calldata actions, AllowedSlippage calldata slippage)
        internal
        pure
        returns (bytes32 result)
    {
        // This function does not check for or clean any dirty bits that might
        // exist in `slippage`. We assume that `slippage` will be used elsewhere
        // in this context and that if there are dirty bits it will result in a
        // revert later.
        bytes32 arrayOfBytesHash = _hashArrayOfBytes(actions);
        assembly ("memory-safe") {
            let ptr := mload(0x40)
            mstore(ptr, ACTIONS_AND_SLIPPAGE_TYPEHASH)
            calldatacopy(add(ptr, 0x20), slippage, 0x60)
            mstore(add(ptr, 0x80), arrayOfBytesHash)
            result := keccak256(ptr, 0xa0)
        }
    }

    function _metaTxnOtcVIP(bytes calldata data, address msgSender, bytes calldata sig) internal DANGEROUS_freeMemory {
        // An optimized path involving a maker/taker in a single trade
        // The OTC order is signed by both maker and taker, validation is
        // performed inside the OtcOrderSettlement so there is no need to
        // validate `sig` against `actions` here
        (
            address recipient,
            ISignatureTransfer.PermitTransferFrom memory makerPermit,
            address maker,
            bytes memory makerSig,
            ISignatureTransfer.PermitTransferFrom memory takerPermit
        ) = abi.decode(
            data,
            (address, ISignatureTransfer.PermitTransferFrom, address, bytes, ISignatureTransfer.PermitTransferFrom)
        );
        fillOtcOrderMetaTxn(recipient, makerPermit, maker, makerSig, takerPermit, msgSender, sig);
    }

    function _metaTxnTransferFrom(bytes calldata data, address msgSender, bytes calldata sig)
        internal
        DANGEROUS_freeMemory
    {
        (address recipient, ISignatureTransfer.PermitTransferFrom memory permit) =
            abi.decode(data, (address, ISignatureTransfer.PermitTransferFrom));
        (ISignatureTransfer.SignatureTransferDetails memory transferDetails,,) =
            _permitToTransferDetails(permit, recipient);

        // We simultaneously transfer-in the taker's tokens and authenticate the
        // metatransaction.
        _transferFrom(permit, transferDetails, msgSender, sig);
    }

    function _metaTxnUniV3VIP(bytes calldata data, address msgSender, bytes calldata sig)
        internal
        DANGEROUS_freeMemory
    {
        (
            address recipient,
            uint256 amountIn,
            uint256 amountOutMin,
            bytes memory path,
            ISignatureTransfer.PermitTransferFrom memory permit
        ) = abi.decode(data, (address, uint256, uint256, bytes, ISignatureTransfer.PermitTransferFrom));
        sellTokenForTokenToUniswapV3MetaTxn(recipient, path, amountIn, amountOutMin, msgSender, permit, sig);
    }

    function executeMetaTxn(
        bytes[] calldata actions,
        AllowedSlippage calldata slippage,
        address msgSender,
        bytes calldata sig
    ) public metaTx(msgSender, _hashActionsAndSlippage(actions, slippage)) {
        if (actions.length != 0) {
            (bytes4 action, bytes calldata data) = actions.decodeCall(0);

            // By forcing the first action to be one of the witness-aware
            // actions, we ensure that the entire sequence of actions is
            // authorized. `msgSender` is the signer of the metatransaction.

            if (action == ISettlerActions.METATXN_SETTLER_OTC_PERMIT2.selector) {
                _metaTxnOtcVIP(data, msgSender, sig);
            } else if (action == ISettlerActions.METATXN_PERMIT2_TRANSFER_FROM.selector) {
                _metaTxnTransferFrom(data, msgSender, sig);
            } else if (action == ISettlerActions.METATXN_UNISWAPV3_PERMIT2_SWAP_EXACT_IN.selector) {
                _metaTxnUniV3VIP(data, msgSender, sig);
            } else {
                revert ActionInvalid({i: 0, action: action, data: data});
            }
        }

        for (uint256 i = 1; i < actions.length; i = i.unsafeInc()) {
            (bytes4 action, bytes calldata data) = actions.decodeCall(i);
            _dispatch(i, action, data, msgSender);
        }

        _checkSlippageAndTransfer(slippage);
    }

    function _dispatch(uint256 i, bytes4 action, bytes calldata data, address msgSender)
        internal
        DANGEROUS_freeMemory
    {
        if (action == ISettlerActions.PERMIT2_TRANSFER_FROM.selector) {
            (address recipient, ISignatureTransfer.PermitTransferFrom memory permit, bytes memory sig) =
                abi.decode(data, (address, ISignatureTransfer.PermitTransferFrom, bytes));
            (ISignatureTransfer.SignatureTransferDetails memory transferDetails,,) =
                _permitToTransferDetails(permit, recipient);
            _transferFrom(permit, transferDetails, msgSender, sig);
        } else if (action == ISettlerActions.SETTLER_OTC_SELF_FUNDED.selector) {
            (
                address recipient,
                ISignatureTransfer.PermitTransferFrom memory permit,
                address maker,
                bytes memory makerSig,
                IERC20 takerToken,
                uint256 maxTakerAmount
            ) = abi.decode(data, (address, ISignatureTransfer.PermitTransferFrom, address, bytes, IERC20, uint256));

            fillOtcOrderSelfFunded(recipient, permit, maker, makerSig, takerToken, maxTakerAmount, msgSender);
        } else if (action == ISettlerActions.UNISWAPV3_SWAP_EXACT_IN.selector) {
            (address recipient, uint256 bips, uint256 amountOutMin, bytes memory path) =
                abi.decode(data, (address, uint256, uint256, bytes));

            sellTokenForTokenToUniswapV3(recipient, path, bips, amountOutMin);
        } else if (action == ISettlerActions.UNISWAPV2_SWAP.selector) {
            (address recipient, address sellToken, address pool, uint8 swapInfo, uint256 bips, uint256 amountOutMin) =
                abi.decode(data, (address, address, address, uint8, uint256, uint256));

            sellToUniswapV2(recipient, sellToken, pool, swapInfo, bips, amountOutMin);
        } else if (action == ISettlerActions.MAKER_PSM_SELL_GEM.selector) {
            (address recipient, uint256 bips, IPSM psm, IERC20Meta gemToken) =
                abi.decode(data, (address, uint256, IPSM, IERC20Meta));

            makerPsmSellGem(recipient, bips, psm, gemToken);
        } else if (action == ISettlerActions.MAKER_PSM_BUY_GEM.selector) {
            (address recipient, uint256 bips, IPSM psm, IERC20Meta gemToken) =
                abi.decode(data, (address, uint256, IPSM, IERC20Meta));

            makerPsmBuyGem(recipient, bips, psm, gemToken);
        } else if (action == ISettlerActions.BASIC_SELL.selector) {
            (address pool, IERC20 sellToken, uint256 proportion, uint256 offset, bytes memory _data) =
                abi.decode(data, (address, IERC20, uint256, uint256, bytes));

            basicSellToPool(pool, sellToken, proportion, offset, _data);
        } else if (action == ISettlerActions.POSITIVE_SLIPPAGE.selector) {
            (address recipient, IERC20 token, uint256 expectedAmount) = abi.decode(data, (address, IERC20, uint256));
            if (token == IERC20(ETH_ADDRESS)) {
                uint256 balance = address(this).balance;
                if (balance > expectedAmount) {
                    unchecked {
                        payable(recipient).safeTransferETH(balance - expectedAmount);
                    }
                }
            } else {
                uint256 balance = token.balanceOf(address(this));
                if (balance > expectedAmount) {
                    unchecked {
                        token.safeTransfer(recipient, balance - expectedAmount);
                    }
                }
            }
        } else {
            revert ActionInvalid({i: i, action: action, data: data});
        }
    }
}

File 2 of 24 : IERC20.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

interface IERC20 {
    function totalSupply() external view returns (uint256);
    function balanceOf(address) external view returns (uint256);
    function transfer(address, uint256) external returns (bool);
    function transferFrom(address, address, uint256) external returns (bool);
    function approve(address, uint256) external returns (bool);
    function allowance(address, address) external view returns (uint256);

    event Transfer(address indexed, address indexed, uint256);
    event Approval(address indexed, address indexed, uint256);
}

interface IERC20Meta is IERC20 {
    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function decimals() external view returns (uint8);
}

File 3 of 24 : ISignatureTransfer.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

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

/// @title SignatureTransfer
/// @notice Handles ERC20 token transfers through signature based actions
/// @dev Requires user's token approval on the Permit2 contract
interface ISignatureTransfer is IEIP712 {
    /// @notice Thrown when the requested amount for a transfer is larger than the permissioned amount
    /// @param maxAmount The maximum amount a spender can request to transfer
    error InvalidAmount(uint256 maxAmount);

    /// @notice Thrown when the number of tokens permissioned to a spender does not match the number of tokens being transferred
    /// @dev If the spender does not need to transfer the number of tokens permitted, the spender can request amount 0 to be transferred
    error LengthMismatch();

    /// @notice Emits an event when the owner successfully invalidates an unordered nonce.
    event UnorderedNonceInvalidation(address indexed owner, uint256 word, uint256 mask);

    /// @notice The token and amount details for a transfer signed in the permit transfer signature
    struct TokenPermissions {
        // ERC20 token address
        address token;
        // the maximum amount that can be spent
        uint256 amount;
    }

    /// @notice The signed permit message for a single token transfer
    struct PermitTransferFrom {
        TokenPermissions permitted;
        // a unique value for every token owner's signature to prevent signature replays
        uint256 nonce;
        // deadline on the permit signature
        uint256 deadline;
    }

    /// @notice Specifies the recipient address and amount for batched transfers.
    /// @dev Recipients and amounts correspond to the index of the signed token permissions array.
    /// @dev Reverts if the requested amount is greater than the permitted signed amount.
    struct SignatureTransferDetails {
        // recipient address
        address to;
        // spender requested amount
        uint256 requestedAmount;
    }

    /// @notice Used to reconstruct the signed permit message for multiple token transfers
    /// @dev Do not need to pass in spender address as it is required that it is msg.sender
    /// @dev Note that a user still signs over a spender address
    struct PermitBatchTransferFrom {
        // the tokens and corresponding amounts permitted for a transfer
        TokenPermissions[] permitted;
        // a unique value for every token owner's signature to prevent signature replays
        uint256 nonce;
        // deadline on the permit signature
        uint256 deadline;
    }

    /// @notice A map from token owner address and a caller specified word index to a bitmap. Used to set bits in the bitmap to prevent against signature replay protection
    /// @dev Uses unordered nonces so that permit messages do not need to be spent in a certain order
    /// @dev The mapping is indexed first by the token owner, then by an index specified in the nonce
    /// @dev It returns a uint256 bitmap
    /// @dev The index, or wordPosition is capped at type(uint248).max
    function nonceBitmap(address, uint256) external view returns (uint256);

    /// @notice Transfers a token using a signed permit message
    /// @dev Reverts if the requested amount is greater than the permitted signed amount
    /// @param permit The permit data signed over by the owner
    /// @param owner The owner of the tokens to transfer
    /// @param transferDetails The spender's requested transfer details for the permitted token
    /// @param signature The signature to verify
    function permitTransferFrom(
        PermitTransferFrom memory permit,
        SignatureTransferDetails calldata transferDetails,
        address owner,
        bytes calldata signature
    ) external;

    /// @notice Transfers a token using a signed permit message
    /// @notice Includes extra data provided by the caller to verify signature over
    /// @dev The witness type string must follow EIP712 ordering of nested structs and must include the TokenPermissions type definition
    /// @dev Reverts if the requested amount is greater than the permitted signed amount
    /// @param permit The permit data signed over by the owner
    /// @param owner The owner of the tokens to transfer
    /// @param transferDetails The spender's requested transfer details for the permitted token
    /// @param witness Extra data to include when checking the user signature
    /// @param witnessTypeString The EIP-712 type definition for remaining string stub of the typehash
    /// @param signature The signature to verify
    function permitWitnessTransferFrom(
        PermitTransferFrom memory permit,
        SignatureTransferDetails calldata transferDetails,
        address owner,
        bytes32 witness,
        string calldata witnessTypeString,
        bytes calldata signature
    ) external;

    /// @notice Transfers multiple tokens using a signed permit message
    /// @param permit The permit data signed over by the owner
    /// @param owner The owner of the tokens to transfer
    /// @param transferDetails Specifies the recipient and requested amount for the token transfer
    /// @param signature The signature to verify
    function permitTransferFrom(
        PermitBatchTransferFrom memory permit,
        SignatureTransferDetails[] calldata transferDetails,
        address owner,
        bytes calldata signature
    ) external;

    /// @notice Transfers multiple tokens using a signed permit message
    /// @dev The witness type string must follow EIP712 ordering of nested structs and must include the TokenPermissions type definition
    /// @notice Includes extra data provided by the caller to verify signature over
    /// @param permit The permit data signed over by the owner
    /// @param owner The owner of the tokens to transfer
    /// @param transferDetails Specifies the recipient and requested amount for the token transfer
    /// @param witness Extra data to include when checking the user signature
    /// @param witnessTypeString The EIP-712 type definition for remaining string stub of the typehash
    /// @param signature The signature to verify
    function permitWitnessTransferFrom(
        PermitBatchTransferFrom memory permit,
        SignatureTransferDetails[] calldata transferDetails,
        address owner,
        bytes32 witness,
        string calldata witnessTypeString,
        bytes calldata signature
    ) external;

    /// @notice Invalidates the bits specified in mask for the bitmap at the word position
    /// @dev The wordPos is maxed at type(uint248).max
    /// @param wordPos A number to index the nonceBitmap at
    /// @param mask A bitmap masked against msg.sender's current bitmap at the word position
    function invalidateUnorderedNonces(uint256 wordPos, uint256 mask) external;
}

File 4 of 24 : Permit2Payment.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

import {ForwarderNotAllowed, InvalidSignatureLen, ConfusedDeputy} from "./SettlerErrors.sol";
import {AllowanceHolderContext} from "../allowanceholder/AllowanceHolderContext.sol";
import {SettlerAbstract} from "../SettlerAbstract.sol";

import {ISignatureTransfer} from "permit2/src/interfaces/ISignatureTransfer.sol";
import {Revert} from "../utils/Revert.sol";

library TransientStorage {
    // bytes32(uint256(keccak256("operator slot")) - 1)
    bytes32 private constant _OPERATOR_SLOT = 0x009355806b743562f351db2e3726091207f49fa1cdccd5c65a7d4860ce3abbe9;
    // bytes32(uint256(keccak256("witness slot")) - 1)
    bytes32 private constant _WITNESS_SLOT = 0x1643bf8e9fdaef48c4abf5a998de359be44a235ac7aebfbc05485e093720deaa;
    // bytes32(uint256(keccak256("metatx signer slot")) - 1)
    bytes32 private constant _METATX_SIGNER_SLOT = 0xfc7be34027b4062d13b31d75182f37b703b5ad960f0e73236593535549bb277d;

    error ReentrantCallback(address oldOperator);

    function setOperator(address operator) internal {
        address currentSigner;
        assembly ("memory-safe") {
            currentSigner := tload(_METATX_SIGNER_SLOT)
        }
        if (operator == currentSigner) {
            revert ConfusedDeputy();
        }
        address currentOperator;
        assembly ("memory-safe") {
            currentOperator := tload(_OPERATOR_SLOT)
        }
        if (currentOperator != address(0) && msg.sender != currentOperator) {
            revert ReentrantCallback(currentOperator);
        }
        assembly ("memory-safe") {
            tstore(_OPERATOR_SLOT, and(0xffffffffffffffffffffffffffffffffffffffff, operator))
        }
    }

    error OperatorNotSpent(address oldOperator);

    function checkSpentOperator() internal view {
        address currentOperator;
        assembly ("memory-safe") {
            currentOperator := tload(_OPERATOR_SLOT)
        }
        if (currentOperator != address(0)) {
            revert OperatorNotSpent(currentOperator);
        }
    }

    function getAndClearOperator() internal returns (address operator) {
        assembly ("memory-safe") {
            operator := tload(_OPERATOR_SLOT)
            if operator { tstore(_OPERATOR_SLOT, 0) }
        }
    }

    error ReentrantMetatransaction(bytes32 oldWitness);

    function setWitness(bytes32 newWitness, address signer) internal {
        bytes32 currentWitness;
        assembly ("memory-safe") {
            currentWitness := tload(_WITNESS_SLOT)
        }
        if (currentWitness != bytes32(0)) {
            revert ReentrantMetatransaction(currentWitness);
        }
        assembly ("memory-safe") {
            tstore(_WITNESS_SLOT, newWitness)
            tstore(_METATX_SIGNER_SLOT, and(0xffffffffffffffffffffffffffffffffffffffff, signer))
        }
    }

    error WitnessNotSpent(bytes32 oldWitness);

    function checkSpentWitness() internal view {
        bytes32 currentWitness;
        assembly ("memory-safe") {
            currentWitness := tload(_WITNESS_SLOT)
        }
        if (currentWitness != bytes32(0)) {
            revert WitnessNotSpent(currentWitness);
        }
    }

    function getAndClearWitness() internal returns (bytes32 witness, address signer) {
        assembly ("memory-safe") {
            witness := tload(_WITNESS_SLOT)
            if witness {
                signer := tload(_METATX_SIGNER_SLOT)
                tstore(_METATX_SIGNER_SLOT, 0)
                tstore(_WITNESS_SLOT, 0)
            }
        }
    }
}

abstract contract Permit2PaymentBase is AllowanceHolderContext, SettlerAbstract {
    using Revert for bool;

    /// @dev Permit2 address
    ISignatureTransfer internal constant _PERMIT2 = ISignatureTransfer(0x000000000022D473030F116dDEE9F6B43aC78BA3);

    function isRestrictedTarget(address target) internal pure override returns (bool) {
        return target == address(_PERMIT2) || target == address(_ALLOWANCE_HOLDER);
    }

    function _setOperatorAndCall(address payable target, uint256 value, bytes memory data)
        internal
        override
        returns (bytes memory)
    {
        TransientStorage.setOperator(target);
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        success.maybeRevert(returndata);
        TransientStorage.checkSpentOperator();
        return returndata;
    }

    function _setOperatorAndCall(address target, bytes memory data) internal override returns (bytes memory) {
        return _setOperatorAndCall(payable(target), 0, data);
    }

    modifier metaTx(address msgSender, bytes32 witness) override {
        TransientStorage.setWitness(witness, msgSender);
        TransientStorage.setOperator(_msgSender());
        _;
        TransientStorage.checkSpentOperator();
        TransientStorage.checkSpentWitness();
    }
}

abstract contract Permit2Payment is Permit2PaymentBase {
    // `string.concat` isn't recognized by solc as compile-time constant, but `abi.encodePacked` is
    // This is defined here as `private` and not in `SettlerAbstract` as `internal` because no other
    // contract/file should reference it. The *ONLY* approved way to make a transfer using this
    // witness string is by setting the witness with `_setWitness`
    string private constant _ACTIONS_AND_SLIPPAGE_WITNESS = string(
        abi.encodePacked("ActionsAndSlippage actionsAndSlippage)", ACTIONS_AND_SLIPPAGE_TYPE, TOKEN_PERMISSIONS_TYPE)
    );

    function _permitToTransferDetails(ISignatureTransfer.PermitTransferFrom memory permit, address recipient)
        internal
        pure
        override
        returns (ISignatureTransfer.SignatureTransferDetails memory transferDetails, address token, uint256 amount)
    {
        transferDetails.to = recipient;
        transferDetails.requestedAmount = amount = permit.permitted.amount;
        token = permit.permitted.token;
    }

    // This function is provided *EXCLUSIVELY* for use here and in OtcOrderSettlement. Any other use
    // of this function is forbidden. You must use the overload that does *NOT* take a `witness`
    // argument.
    function _transferFrom(
        ISignatureTransfer.PermitTransferFrom memory permit,
        ISignatureTransfer.SignatureTransferDetails memory transferDetails,
        address from,
        bytes32 witness,
        string memory witnessTypeString,
        bytes memory sig,
        bool isForwarded
    ) internal override {
        if (isForwarded) revert ForwarderNotAllowed();
        _PERMIT2.permitWitnessTransferFrom(permit, transferDetails, from, witness, witnessTypeString, sig);
    }

    // See comment in above overload
    function _transferFrom(
        ISignatureTransfer.PermitTransferFrom memory permit,
        ISignatureTransfer.SignatureTransferDetails memory transferDetails,
        address from,
        bytes32 witness,
        string memory witnessTypeString,
        bytes memory sig
    ) internal override {
        _transferFrom(permit, transferDetails, from, witness, witnessTypeString, sig, _isForwarded());
    }

    function _transferFrom(
        ISignatureTransfer.PermitTransferFrom memory permit,
        ISignatureTransfer.SignatureTransferDetails memory transferDetails,
        address from,
        bytes memory sig,
        bool isForwarded
    ) internal override {
        if (from != _msgSender() && msg.sender != TransientStorage.getAndClearOperator()) {
            revert ConfusedDeputy();
        }
        {
            (bytes32 witness, address signer) = TransientStorage.getAndClearWitness();
            if (witness != bytes32(0)) {
                if (from != signer) {
                    revert ConfusedDeputy();
                }
                return _transferFrom(
                    permit, transferDetails, from, witness, _ACTIONS_AND_SLIPPAGE_WITNESS, sig, isForwarded
                );
            }
        }
        if (isForwarded) {
            if (sig.length != 0) revert InvalidSignatureLen();
            _ALLOWANCE_HOLDER.transferFrom(
                permit.permitted.token, from, transferDetails.to, transferDetails.requestedAmount
            );
        } else {
            _PERMIT2.permitTransferFrom(permit, transferDetails, from, sig);
        }
    }

    function _transferFrom(
        ISignatureTransfer.PermitTransferFrom memory permit,
        ISignatureTransfer.SignatureTransferDetails memory transferDetails,
        address from,
        bytes memory sig
    ) internal override {
        _transferFrom(permit, transferDetails, from, sig, _isForwarded());
    }
}

File 5 of 24 : Basic.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

import {SettlerAbstract} from "../SettlerAbstract.sol";
import {InvalidOffset, ConfusedDeputy, InvalidTarget} from "./SettlerErrors.sol";

import {IERC20} from "../IERC20.sol";
import {SafeTransferLib} from "../vendor/SafeTransferLib.sol";
import {FullMath} from "../vendor/FullMath.sol";
import {Panic} from "../utils/Panic.sol";
import {Revert} from "../utils/Revert.sol";

abstract contract Basic is SettlerAbstract {
    using SafeTransferLib for IERC20;
    using FullMath for uint256;
    using Revert for bool;

    address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;

    /// @dev Sell to a pool with a generic approval, transferFrom interaction.
    /// offset in the calldata is used to update the sellAmount given a proportion of the sellToken balance
    function basicSellToPool(address pool, IERC20 sellToken, uint256 bips, uint256 offset, bytes memory data)
        internal
    {
        if (isRestrictedTarget(pool)) {
            revert ConfusedDeputy();
        }

        bool success;
        bytes memory returnData;
        uint256 value;
        if (sellToken == IERC20(ETH_ADDRESS)) {
            value = address(this).balance.mulDiv(bips, 10_000);
            if (data.length == 0) {
                if (offset != 0) revert InvalidOffset();
                (success, returnData) = payable(pool).call{value: value}("");
                success.maybeRevert(returnData);
                return;
            } else {
                if ((offset += 32) > data.length) {
                    Panic.panic(Panic.ARRAY_OUT_OF_BOUNDS);
                }
                assembly ("memory-safe") {
                    mstore(add(data, offset), value)
                }
            }
        } else if (address(sellToken) == address(0)) {
            if (offset != 0) revert InvalidOffset();
        } else {
            uint256 amount = sellToken.balanceOf(address(this)).mulDiv(bips, 10_000);
            if ((offset += 32) > data.length) {
                Panic.panic(Panic.ARRAY_OUT_OF_BOUNDS);
            }
            assembly ("memory-safe") {
                mstore(add(data, offset), amount)
            }
            if (address(sellToken) != pool) {
                sellToken.safeApproveIfBelow(pool, amount);
            }
        }
        (success, returnData) = payable(pool).call{value: value}(data);
        success.maybeRevert(returnData);
        // forbid sending data to EOAs
        if (returnData.length == 0 && pool.code.length == 0) revert InvalidTarget();
    }
}

File 6 of 24 : OtcOrderSettlement.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

import {IERC20} from "../IERC20.sol";
import {ISignatureTransfer} from "permit2/src/interfaces/ISignatureTransfer.sol";
import {SettlerAbstract} from "../SettlerAbstract.sol";

import {SafeTransferLib} from "../vendor/SafeTransferLib.sol";
import {FullMath} from "../vendor/FullMath.sol";

abstract contract OtcOrderSettlement is SettlerAbstract {
    using SafeTransferLib for IERC20;
    using FullMath for uint256;

    struct Consideration {
        address token;
        uint256 amount;
        address counterparty;
        bool partialFillAllowed;
    }

    string internal constant CONSIDERATION_TYPE =
        "Consideration(address token,uint256 amount,address counterparty,bool partialFillAllowed)";
    // `string.concat` isn't recognized by solc as compile-time constant, but `abi.encodePacked` is
    string internal constant CONSIDERATION_WITNESS =
        string(abi.encodePacked("Consideration consideration)", CONSIDERATION_TYPE, TOKEN_PERMISSIONS_TYPE));
    bytes32 internal constant CONSIDERATION_TYPEHASH =
        0x7d806873084f389a66fd0315dead7adaad8ae6e8b6cf9fb0d3db61e5a91c3ffa;

    string internal constant OTC_ORDER_TYPE =
        "OtcOrder(Consideration makerConsideration,Consideration takerConsideration)";
    string internal constant OTC_ORDER_TYPE_RECURSIVE = string(abi.encodePacked(OTC_ORDER_TYPE, CONSIDERATION_TYPE));
    bytes32 internal constant OTC_ORDER_TYPEHASH = 0x4efcac36537dd5721596376472101aec5ff380b23b286c66cdfe70a509c0cef3;

    function _hashConsideration(Consideration memory consideration) internal pure returns (bytes32 result) {
        assembly ("memory-safe") {
            let ptr := sub(consideration, 0x20)
            let oldValue := mload(ptr)
            mstore(ptr, CONSIDERATION_TYPEHASH)
            result := keccak256(ptr, 0xa0)
            mstore(ptr, oldValue)
        }
    }

    function _logOtcOrder(bytes32 makerConsiderationHash, bytes32 takerConsiderationHash, uint128 makerFilledAmount)
        private
    {
        assembly ("memory-safe") {
            mstore(0x00, OTC_ORDER_TYPEHASH)
            mstore(0x20, makerConsiderationHash)
            let ptr := mload(0x40)
            mstore(0x40, takerConsiderationHash)
            let orderHash := keccak256(0x00, 0x60)
            mstore(0x40, ptr)
            mstore(0x10, makerFilledAmount)
            mstore(0x00, orderHash)
            log0(0x00, 0x30)
        }
    }

    constructor() {
        assert(CONSIDERATION_TYPEHASH == keccak256(bytes(CONSIDERATION_TYPE)));
        assert(OTC_ORDER_TYPEHASH == keccak256(bytes(OTC_ORDER_TYPE_RECURSIVE)));
    }

    /// @dev Settle an OtcOrder between maker and taker transferring funds directly between
    /// the counterparties. Either two Permit2 signatures are consumed, with the maker Permit2 containing
    /// a witness of the OtcOrder, or AllowanceHolder is supported for the taker payment.
    function fillOtcOrder(
        address recipient,
        ISignatureTransfer.PermitTransferFrom memory makerPermit,
        address maker,
        bytes memory makerSig,
        ISignatureTransfer.PermitTransferFrom memory takerPermit,
        bytes memory takerSig
    ) internal {
        return fillOtcOrderMetaTxn(recipient, makerPermit, maker, makerSig, takerPermit, _msgSender(), takerSig);
    }

    /// @dev Settle an OtcOrder between maker and taker transfering funds directly between
    /// the counterparties. Both Maker and Taker have signed the same order, and submission
    /// is via a third party
    /// @dev the taker's witness is not calculated nor verified here as calling function is trusted
    function fillOtcOrderMetaTxn(
        address recipient,
        ISignatureTransfer.PermitTransferFrom memory makerPermit,
        address maker,
        bytes memory makerSig,
        ISignatureTransfer.PermitTransferFrom memory takerPermit,
        address taker,
        bytes memory takerSig
    ) internal {
        (
            ISignatureTransfer.SignatureTransferDetails memory makerTransferDetails,
            address makerToken,
            uint256 makerAmount
        ) = _permitToTransferDetails(makerPermit, recipient);
        (
            ISignatureTransfer.SignatureTransferDetails memory takerTransferDetails,
            address takerToken,
            uint256 takerAmount
        ) = _permitToTransferDetails(takerPermit, maker);

        bytes32 witness = _hashConsideration(
            Consideration({token: takerToken, amount: takerAmount, counterparty: taker, partialFillAllowed: false})
        );
        _transferFrom(takerPermit, takerTransferDetails, taker, takerSig);
        _transferFrom(makerPermit, makerTransferDetails, maker, witness, CONSIDERATION_WITNESS, makerSig, false);

        _logOtcOrder(
            witness,
            _hashConsideration(
                Consideration({token: makerToken, amount: makerAmount, counterparty: maker, partialFillAllowed: false})
            ),
            uint128(makerAmount)
        );
    }

    /// @dev Settle an OtcOrder between maker and Settler retaining funds in this contract.
    /// @dev pre-condition: msgSender has been authenticated against the requestor
    /// One Permit2 signature is consumed, with the maker Permit2 containing a witness of the OtcOrder.
    // In this variant, Maker pays recipient and Settler pays Maker
    function fillOtcOrderSelfFunded(
        address recipient,
        ISignatureTransfer.PermitTransferFrom memory permit,
        address maker,
        bytes memory makerSig,
        IERC20 takerToken,
        uint256 maxTakerAmount,
        address msgSender
    ) internal {
        ISignatureTransfer.SignatureTransferDetails memory transferDetails;
        Consideration memory takerConsideration;
        takerConsideration.partialFillAllowed = true;
        uint256 buyAmount;
        (transferDetails, takerConsideration.token, buyAmount) = _permitToTransferDetails(permit, recipient);
        takerConsideration.amount = buyAmount;
        takerConsideration.counterparty = maker;

        Consideration memory makerConsideration = Consideration({
            token: address(takerToken),
            amount: maxTakerAmount,
            counterparty: msgSender,
            partialFillAllowed: true
        });
        bytes32 witness = _hashConsideration(makerConsideration);

        uint256 takerAmount = takerToken.balanceOf(address(this));
        if (takerAmount > maxTakerAmount) {
            takerAmount = maxTakerAmount;
        }
        transferDetails.requestedAmount = transferDetails.requestedAmount.unsafeMulDiv(takerAmount, maxTakerAmount);

        takerToken.safeTransfer(maker, takerAmount);
        _transferFrom(permit, transferDetails, maker, witness, CONSIDERATION_WITNESS, makerSig, false);

        _logOtcOrder(witness, _hashConsideration(takerConsideration), uint128(buyAmount));
    }
}

File 7 of 24 : UniswapV3.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

import {IERC20} from "../IERC20.sol";
import {ISignatureTransfer} from "permit2/src/interfaces/ISignatureTransfer.sol";
import {UnsafeMath} from "../utils/UnsafeMath.sol";
import {Panic} from "../utils/Panic.sol";
import {SafeTransferLib} from "../vendor/SafeTransferLib.sol";
import {AddressDerivation} from "../utils/AddressDerivation.sol";
import {SettlerAbstract} from "../SettlerAbstract.sol";

import {TooMuchSlippage, ConfusedDeputy} from "./SettlerErrors.sol";

interface IUniswapV3Pool {
    /// @notice Swap token0 for token1, or token1 for token0
    /// @dev The caller of this method receives a callback in the form of IUniswapV3SwapCallback#uniswapV3SwapCallback
    /// @param recipient The address to receive the output of the swap
    /// @param zeroForOne The direction of the swap, true for token0 to token1, false for token1 to token0
    /// @param amountSpecified The amount of the swap, which implicitly configures the swap as exact input (positive),
    /// or exact output (negative)
    /// @param sqrtPriceLimitX96 The Q64.96 sqrt price limit. If zero for one, the price cannot be less than this
    /// value after the swap. If one for zero, the price cannot be greater than this value after the swap
    /// @param data Any data to be passed through to the callback
    /// @return amount0 The delta of the balance of token0 of the pool, exact when negative, minimum when positive
    /// @return amount1 The delta of the balance of token1 of the pool, exact when negative, minimum when positive
    function swap(
        address recipient,
        bool zeroForOne,
        int256 amountSpecified,
        uint160 sqrtPriceLimitX96,
        bytes calldata data
    ) external returns (int256 amount0, int256 amount1);
}

abstract contract UniswapV3 is SettlerAbstract {
    using UnsafeMath for uint256;
    using SafeTransferLib for IERC20;

    /// @dev UniswapV3 Factory contract address
    address private immutable UNI_FACTORY_ADDRESS;
    /// @dev UniswapV3 pool init code hash.
    bytes32 private immutable UNI_POOL_INIT_CODE_HASH;
    /// @dev Minimum size of an encoded swap path:
    ///      sizeof(address(inputToken) | uint24(fee) | address(outputToken))
    uint256 private constant SINGLE_HOP_PATH_SIZE = 0x2b;
    /// @dev How many bytes to skip ahead in an encoded path to start at the next hop:
    ///      sizeof(address(inputToken) | uint24(fee))
    uint256 private constant PATH_SKIP_HOP_SIZE = 0x17;
    /// @dev The size of the swap callback prefix data before the Permit2 data.
    uint256 private constant SWAP_CALLBACK_PREFIX_DATA_SIZE = 0x3f;
    /// @dev The offset from the pointer to the length of the swap callback prefix data to the start of the Permit2 data.
    uint256 private constant SWAP_CALLBACK_PERMIT2DATA_OFFSET = 0x5f;
    uint256 private constant PERMIT_DATA_SIZE = 0x80;
    uint256 private constant ISFORWARDED_DATA_SIZE = 0x20;
    /// @dev Minimum tick price sqrt ratio.
    uint160 private constant MIN_PRICE_SQRT_RATIO = 4295128739;
    /// @dev Minimum tick price sqrt ratio.
    uint160 private constant MAX_PRICE_SQRT_RATIO = 1461446703485210103287273052203988822378723970342;
    /// @dev Mask of lower 20 bytes.
    uint256 private constant ADDRESS_MASK = 0x00ffffffffffffffffffffffffffffffffffffffff;
    /// @dev Mask of lower 3 bytes.
    uint256 private constant UINT24_MASK = 0xffffff;

    constructor(address uniFactory, bytes32 poolInitCodeHash) {
        UNI_FACTORY_ADDRESS = uniFactory;
        UNI_POOL_INIT_CODE_HASH = poolInitCodeHash;
    }

    /// @dev Sell a token for another token directly against uniswap v3.
    /// @param encodedPath Uniswap-encoded path.
    /// @param bips proportion of current balance of the first token in the path to sell.
    /// @param minBuyAmount Minimum amount of the last token in the path to buy.
    /// @param recipient The recipient of the bought tokens.
    /// @return buyAmount Amount of the last token in the path bought.
    function sellTokenForTokenToUniswapV3(
        address recipient,
        bytes memory encodedPath,
        uint256 bips,
        uint256 minBuyAmount
    ) internal returns (uint256 buyAmount) {
        buyAmount = _swap(
            recipient,
            encodedPath,
            // We don't care about phantom overflow here because reserves are
            // limited to 128 bits. Any token balance that would overflow here
            // would also break UniV3.
            (IERC20(address(bytes20(encodedPath))).balanceOf(address(this)) * bips).unsafeDiv(10_000),
            minBuyAmount,
            address(this), // payer
            new bytes(SWAP_CALLBACK_PREFIX_DATA_SIZE)
        );
    }

    /// @dev Sell a token for another token directly against uniswap v3. Payment is using a Permit2 signature.
    /// @param encodedPath Uniswap-encoded path.
    /// @param sellAmount amount of the first token in the path to sell.
    /// @param minBuyAmount Minimum amount of the last token in the path to buy.
    /// @param recipient The recipient of the bought tokens.
    /// @param permit The PermitTransferFrom allowing this contract to spend the taker's tokens
    /// @param sig The taker's signature for Permit2
    /// @return buyAmount Amount of the last token in the path bought.
    function sellTokenForTokenToUniswapV3VIP(
        address recipient,
        bytes memory encodedPath,
        uint256 sellAmount,
        uint256 minBuyAmount,
        ISignatureTransfer.PermitTransferFrom memory permit,
        bytes memory sig
    ) internal returns (uint256 buyAmount) {
        bytes memory swapCallbackData =
            new bytes(SWAP_CALLBACK_PREFIX_DATA_SIZE + PERMIT_DATA_SIZE + ISFORWARDED_DATA_SIZE + sig.length);
        _encodePermit2Data(swapCallbackData, permit, sig, _isForwarded());

        buyAmount = _swap(recipient, encodedPath, sellAmount, minBuyAmount, _msgSender(), swapCallbackData);
    }

    /// @dev Sell a token for another token directly against uniswap v3. Payment is using a Permit2 signature.
    /// @param encodedPath Uniswap-encoded path.
    /// @param sellAmount amount of the first token in the path to sell.
    /// @param minBuyAmount Minimum amount of the last token in the path to buy.
    /// @param recipient The recipient of the bought tokens.
    /// @param payer The taker of the transaction and the signer of the permit
    /// @param permit The PermitTransferFrom allowing this contract to spend the taker's tokens
    /// @param sig The taker's signature for Permit2
    /// @return buyAmount Amount of the last token in the path bought.
    function sellTokenForTokenToUniswapV3MetaTxn(
        address recipient,
        bytes memory encodedPath,
        uint256 sellAmount,
        uint256 minBuyAmount,
        address payer,
        ISignatureTransfer.PermitTransferFrom memory permit,
        bytes memory sig
    ) internal returns (uint256 buyAmount) {
        bytes memory swapCallbackData =
            new bytes(SWAP_CALLBACK_PREFIX_DATA_SIZE + PERMIT_DATA_SIZE + ISFORWARDED_DATA_SIZE + sig.length);
        _encodePermit2Data(swapCallbackData, permit, sig, false);

        buyAmount = _swap(recipient, encodedPath, sellAmount, minBuyAmount, payer, swapCallbackData);
    }

    // Executes successive swaps along an encoded uniswap path.
    function _swap(
        address recipient,
        bytes memory encodedPath,
        uint256 sellAmount,
        uint256 minBuyAmount,
        address payer,
        bytes memory swapCallbackData
    ) private returns (uint256 buyAmount) {
        if (sellAmount > uint256(type(int256).max)) {
            Panic.panic(Panic.ARITHMETIC_OVERFLOW);
        }

        IERC20 outputToken;
        while (true) {
            bool isPathMultiHop = _isPathMultiHop(encodedPath);
            bool zeroForOne;
            IUniswapV3Pool pool;
            {
                (IERC20 token0, uint24 fee, IERC20 token1) = _decodeFirstPoolInfoFromPath(encodedPath);
                outputToken = token1;
                if (!(zeroForOne = token0 < token1)) {
                    (token0, token1) = (token1, token0);
                }
                pool = _toPool(token0, fee, token1);
                _updateSwapCallbackData(swapCallbackData, token0, fee, token1, payer);
            }

            int256 amount0;
            int256 amount1;
            if (payer == address(this)) {
                (amount0, amount1) = pool.swap(
                    // Intermediate tokens go to this contract.
                    isPathMultiHop ? address(this) : recipient,
                    zeroForOne,
                    int256(sellAmount),
                    zeroForOne ? MIN_PRICE_SQRT_RATIO + 1 : MAX_PRICE_SQRT_RATIO - 1,
                    swapCallbackData
                );
            } else {
                (amount0, amount1) = abi.decode(
                    _setOperatorAndCall(
                        address(pool),
                        abi.encodeCall(
                            pool.swap,
                            (
                                // Intermediate tokens go to this contract.
                                isPathMultiHop ? address(this) : recipient,
                                zeroForOne,
                                int256(sellAmount),
                                zeroForOne ? MIN_PRICE_SQRT_RATIO + 1 : MAX_PRICE_SQRT_RATIO - 1,
                                swapCallbackData
                            )
                        )
                    ),
                    (int256, int256)
                );
            }

            {
                int256 _buyAmount = -(zeroForOne ? amount1 : amount0);
                if (_buyAmount < 0) {
                    Panic.panic(Panic.ARITHMETIC_OVERFLOW);
                }
                buyAmount = uint256(_buyAmount);
            }
            if (!isPathMultiHop) {
                // Done.
                break;
            }
            // Continue with next hop.
            payer = address(this); // Subsequent hops are paid for by us.
            sellAmount = buyAmount;
            // Skip to next hop along path.
            encodedPath = _shiftHopFromPathInPlace(encodedPath);
            assembly ("memory-safe") {
                mstore(swapCallbackData, SWAP_CALLBACK_PREFIX_DATA_SIZE)
            }
        }
        if (buyAmount < minBuyAmount) {
            revert TooMuchSlippage(address(outputToken), minBuyAmount, buyAmount);
        }
    }

    // Return whether or not an encoded uniswap path contains more than one hop.
    function _isPathMultiHop(bytes memory encodedPath) private pure returns (bool) {
        return encodedPath.length > SINGLE_HOP_PATH_SIZE;
    }

    function _decodeFirstPoolInfoFromPath(bytes memory encodedPath)
        private
        pure
        returns (IERC20 inputToken, uint24 fee, IERC20 outputToken)
    {
        if (encodedPath.length < SINGLE_HOP_PATH_SIZE) {
            Panic.panic(Panic.ARRAY_OUT_OF_BOUNDS);
        }
        assembly ("memory-safe") {
            // Solidity cleans dirty bits automatically
            inputToken := mload(add(encodedPath, 0x14))
            fee := mload(add(encodedPath, 0x17))
            outputToken := mload(add(encodedPath, SINGLE_HOP_PATH_SIZE))
        }
    }

    // Skip past the first hop of an encoded uniswap path in-place.
    function _shiftHopFromPathInPlace(bytes memory encodedPath) private pure returns (bytes memory) {
        if (encodedPath.length < PATH_SKIP_HOP_SIZE) {
            Panic.panic(Panic.ARRAY_OUT_OF_BOUNDS);
        }
        assembly ("memory-safe") {
            let length := sub(mload(encodedPath), PATH_SKIP_HOP_SIZE)
            encodedPath := add(encodedPath, PATH_SKIP_HOP_SIZE)
            mstore(encodedPath, length)
        }
        return encodedPath;
    }

    function _encodePermit2Data(
        bytes memory swapCallbackData,
        ISignatureTransfer.PermitTransferFrom memory permit,
        bytes memory sig,
        bool isForwarded
    ) private pure {
        assembly ("memory-safe") {
            {
                let permitted := mload(permit)
                mstore(add(swapCallbackData, SWAP_CALLBACK_PERMIT2DATA_OFFSET), mload(permitted))
                mstore(add(swapCallbackData, add(SWAP_CALLBACK_PERMIT2DATA_OFFSET, 0x20)), mload(add(permitted, 0x20)))
            }
            mstore(add(swapCallbackData, add(SWAP_CALLBACK_PERMIT2DATA_OFFSET, 0x40)), mload(add(permit, 0x20)))
            mstore(add(swapCallbackData, add(SWAP_CALLBACK_PERMIT2DATA_OFFSET, 0x60)), mload(add(permit, 0x40)))
            mstore(add(swapCallbackData, add(SWAP_CALLBACK_PERMIT2DATA_OFFSET, PERMIT_DATA_SIZE)), and(isForwarded, 1))
            mcopy(
                add(
                    swapCallbackData,
                    add(add(SWAP_CALLBACK_PERMIT2DATA_OFFSET, PERMIT_DATA_SIZE), ISFORWARDED_DATA_SIZE)
                ),
                add(sig, 0x20),
                mload(sig)
            )
        }
    }

    // Update `swapCallbackData` in place with new values.
    function _updateSwapCallbackData(
        bytes memory swapCallbackData,
        IERC20 token0,
        uint24 fee,
        IERC20 token1,
        address payer
    ) private pure {
        assembly ("memory-safe") {
            let length := mload(swapCallbackData)
            mstore(add(swapCallbackData, 0x3f), payer)
            mstore(add(swapCallbackData, 0x2b), token1)
            mstore(add(swapCallbackData, 0x17), fee)
            mstore(add(swapCallbackData, 0x14), token0)
            mstore(swapCallbackData, length)
        }
    }

    // Compute the pool address given two tokens and a fee.
    function _toPool(IERC20 inputToken, uint24 fee, IERC20 outputToken) private view returns (IUniswapV3Pool) {
        // address(keccak256(abi.encodePacked(
        //     hex"ff",
        //     UNI_FACTORY_ADDRESS,
        //     keccak256(abi.encode(inputToken, outputToken, fee)),
        //     UNI_POOL_INIT_CODE_HASH
        // )))
        (IERC20 token0, IERC20 token1) =
            inputToken < outputToken ? (inputToken, outputToken) : (outputToken, inputToken);
        bytes32 salt;
        assembly ("memory-safe") {
            let ptr := mload(0x40)
            mstore(0x00, and(ADDRESS_MASK, token0))
            mstore(0x20, and(ADDRESS_MASK, token1))
            mstore(0x40, and(UINT24_MASK, fee))
            salt := keccak256(0x00, 0x60)
            mstore(0x40, ptr)
        }
        return IUniswapV3Pool(
            AddressDerivation.deriveDeterministicContract(UNI_FACTORY_ADDRESS, salt, UNI_POOL_INIT_CODE_HASH)
        );
    }

    error ZeroSwapAmount();

    /// @dev The UniswapV3 pool swap callback which pays the funds requested
    ///      by the caller/pool to the pool. Can only be called by a valid
    ///      UniswapV3 pool.
    /// @param amount0Delta Token0 amount owed.
    /// @param amount1Delta Token1 amount owed.
    /// @param data Arbitrary data forwarded from swap() caller. A packed encoding of: inputToken, outputToken, fee, payer, permit
    function uniswapV3SwapCallback(int256 amount0Delta, int256 amount1Delta, bytes calldata data) external {
        // Decode the data.
        IERC20 token0;
        uint24 fee;
        IERC20 token1;
        address payer;
        assembly ("memory-safe") {
            {
                let firstWord := calldataload(data.offset)
                token0 := shr(0x60, firstWord)
                fee := shr(0x48, firstWord)
            }
            token1 := calldataload(add(data.offset, 0xb))
            payer := calldataload(add(data.offset, 0x1f))
        }
        if (msg.sender != address(_toPool(token0, fee, token1))) {
            revert ConfusedDeputy();
        }

        bytes calldata permit2Data = data[SWAP_CALLBACK_PREFIX_DATA_SIZE:];
        // Pay the amount owed to the pool.
        if (amount0Delta > 0) {
            _pay(token0, payer, uint256(amount0Delta), permit2Data);
        } else if (amount1Delta > 0) {
            _pay(token1, payer, uint256(amount1Delta), permit2Data);
        } else {
            revert ZeroSwapAmount();
        }
    }

    function _pay(IERC20 token, address payer, uint256 amount, bytes calldata permit2Data) private {
        if (payer == address(this)) {
            token.safeTransfer(msg.sender, amount);
        } else {
            (ISignatureTransfer.PermitTransferFrom memory permit, bool isForwarded) =
                abi.decode(permit2Data, (ISignatureTransfer.PermitTransferFrom, bool));
            bytes calldata sig = permit2Data[PERMIT_DATA_SIZE + ISFORWARDED_DATA_SIZE:];
            (ISignatureTransfer.SignatureTransferDetails memory transferDetails,,) =
                _permitToTransferDetails(permit, msg.sender);
            _transferFrom(permit, transferDetails, payer, sig, isForwarded);
        }
    }
}

File 8 of 24 : UniswapV2.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

import {IERC20} from "../IERC20.sol";
import {UnsafeMath} from "../utils/UnsafeMath.sol";
import {Panic} from "../utils/Panic.sol";
import {TooMuchSlippage} from "./SettlerErrors.sol";

interface IUniV2Pair {
    function token0() external view returns (address);
    function token1() external view returns (address);
    function getReserves() external view returns (uint112, uint112, uint32);
    function swap(uint256, uint256, address, bytes calldata) external;
}

abstract contract UniswapV2 {
    using UnsafeMath for uint256;

    // bytes4(keccak256("getReserves()"))
    uint32 private constant UNI_PAIR_RESERVES_SELECTOR = 0x0902f1ac;
    // bytes4(keccak256("swap(uint256,uint256,address,bytes)"))
    uint32 private constant UNI_PAIR_SWAP_SELECTOR = 0x022c0d9f;
    // bytes4(keccak256("transfer(address,uint256)"))
    uint32 private constant ERC20_TRANSFER_SELECTOR = 0xa9059cbb;
    // bytes4(keccak256("balanceOf(address)"))
    uint32 private constant ERC20_BALANCEOF_SELECTOR = 0x70a08231;

    /// @dev Sell a token for another token using UniswapV2.
    function sellToUniswapV2(
        address recipient,
        address sellToken,
        address pool,
        uint8 swapInfo,
        uint256 bips,
        uint256 minBuyAmount
    ) internal {
        // Preventing calls to Permit2 or AH is not explicitly required as neither of these contracts implement the `swap` nor `transfer` selector

        // |7|6|5|4|3|2|1|0| - bit positions in swapInfo (uint8)
        // |0|0|0|0|0|0|F|Z| - Z: zeroForOne flag, F: sellTokenHasFee flag
        bool zeroForOne = (swapInfo & 1) == 1; // Extract the least significant bit (bit 0)
        bool sellTokenHasFee = (swapInfo & 2) >> 1 == 1; // Extract the second least significant bit (bit 1) and shift it right

        uint256 sellAmount;
        uint256 buyAmount;
        // If bips is zero we assume there are no funds within this contract, skip the updating sellAmount.
        // This case occurs if the pool is being chained, in which the funds have been sent directly to the pool
        if (bips != 0) {
            // We don't care about phantom overflow here because reserves are
            // limited to 112 bits. Any token balance that would overflow here would
            // also break UniV2.
            // It is *possible* to set `bips` above the basis and therefore
            // cause an overflow on this multiplication. However, `bips` is
            // passed as authenticated calldata, so this is a GIGO error that we
            // do not attempt to fix.
            unchecked {
                sellAmount = (IERC20(sellToken).balanceOf(address(this)) * bips).unsafeDiv(10_000);
            }
        }
        assembly ("memory-safe") {
            let ptr := mload(0x40)

            // transfer sellAmount (a non zero amount) of sellToken to the pool
            if sellAmount {
                mstore(ptr, ERC20_TRANSFER_SELECTOR)
                mstore(add(ptr, 0x20), pool)
                mstore(add(ptr, 0x40), sellAmount)
                // ...||ERC20_TRANSFER_SELECTOR|pool|sellAmount|
                if iszero(call(gas(), sellToken, 0, add(ptr, 0x1c), 0x44, 0x00, 0x20)) { bubbleRevert(ptr) }
                if iszero(or(iszero(returndatasize()), and(iszero(lt(returndatasize(), 0x20)), eq(mload(0x00), 1)))) {
                    revert(0, 0)
                }
            }

            // get pool reserves
            let sellReserve
            let buyReserve
            mstore(0x00, UNI_PAIR_RESERVES_SELECTOR)
            // ||UNI_PAIR_RESERVES_SELECTOR|
            if iszero(staticcall(gas(), pool, 0x1c, 0x04, 0x00, 0x40)) { bubbleRevert(ptr) }
            if lt(returndatasize(), 0x40) { revert(0, 0) }
            {
                let r := shl(5, zeroForOne)
                buyReserve := mload(r)
                sellReserve := mload(xor(0x20, r))
            }

            // Update the sell amount in the following cases:
            //   the funds are in the pool already (flagged by sellAmount being 0)
            //   the sell token has a fee (flagged by sellTokenHasFee)
            if or(iszero(sellAmount), sellTokenHasFee) {
                // retrieve the sellToken balance of the pool
                mstore(0x00, ERC20_BALANCEOF_SELECTOR)
                mstore(0x20, and(0xffffffffffffffffffffffffffffffffffffffff, pool))
                // ||ERC20_BALANCEOF_SELECTOR|pool|
                if iszero(staticcall(gas(), sellToken, 0x1c, 0x24, 0x00, 0x20)) { bubbleRevert(ptr) }
                if lt(returndatasize(), 0x20) { revert(0, 0) }
                let bal := mload(0x00)

                // determine real sellAmount by comparing pool's sellToken balance to reserve amount
                if lt(bal, sellReserve) {
                    mstore(0x00, 0x4e487b71) // selector for `Panic(uint256)`
                    mstore(0x20, 0x11) // panic code for arithmetic underflow
                    revert(0x1c, 0x24)
                }
                sellAmount := sub(bal, sellReserve)
            }

            // compute buyAmount based on sellAmount and reserves
            let sellAmountWithFee := mul(sellAmount, 997)
            buyAmount := div(mul(sellAmountWithFee, buyReserve), add(sellAmountWithFee, mul(sellReserve, 1000)))
            let swapCalldata := add(ptr, 0x1c)
            // set up swap call selector and empty callback data
            mstore(ptr, UNI_PAIR_SWAP_SELECTOR)
            mstore(add(ptr, 0x80), 0x80) // offset to length of data
            mstore(add(ptr, 0xa0), 0) // length of data

            // set amount0Out and amount1Out
            {
                // If `zeroForOne`, offset is 0x24, else 0x04
                let offset := add(0x04, shl(5, zeroForOne))
                mstore(add(swapCalldata, offset), buyAmount)
                mstore(add(swapCalldata, xor(0x20, offset)), 0)
            }

            mstore(add(swapCalldata, 0x44), and(0xffffffffffffffffffffffffffffffffffffffff, recipient))
            // ...||UNI_PAIR_SWAP_SELECTOR|amount0Out|amount1Out|recipient|data|

            // perform swap at the pool sending bought tokens to the recipient
            if iszero(call(gas(), pool, 0, swapCalldata, 0xa4, 0, 0)) { bubbleRevert(swapCalldata) }

            // revert with the return data from the most recent call
            function bubbleRevert(p) {
                returndatacopy(p, 0, returndatasize())
                revert(p, returndatasize())
            }
        }
        if (buyAmount < minBuyAmount) {
            revert TooMuchSlippage(
                zeroForOne ? IUniV2Pair(pool).token1() : IUniV2Pair(pool).token0(), minBuyAmount, sellAmount
            );
        }
    }
}

File 9 of 24 : MakerPSM.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

import {IERC20, IERC20Meta} from "../IERC20.sol";

import {SafeTransferLib} from "../vendor/SafeTransferLib.sol";
import {UnsafeMath} from "../utils/UnsafeMath.sol";

interface IPSM {
    /// @dev Get the fee for selling DAI to USDC in PSM
    /// @return tout toll out [wad]
    function tout() external view returns (uint256);

    /// @dev Get the address of the underlying vault powering PSM
    /// @return address of gemJoin contract
    function gemJoin() external view returns (address);

    /// @dev Sell USDC for DAI
    /// @param usr The address of the account trading USDC for DAI.
    /// @param gemAmt The amount of USDC to sell in USDC base units
    function sellGem(address usr, uint256 gemAmt) external;

    /// @dev Buy USDC for DAI
    /// @param usr The address of the account trading DAI for USDC
    /// @param gemAmt The amount of USDC to buy in USDC base units
    function buyGem(address usr, uint256 gemAmt) external;
}

abstract contract MakerPSM {
    using UnsafeMath for uint256;
    using SafeTransferLib for IERC20;
    using SafeTransferLib for IERC20Meta;

    // Maker units https://github.com/makerdao/dss/blob/master/DEVELOPING.md
    // wad: fixed point decimal with 18 decimals (for basic quantities, e.g. balances)
    uint256 internal constant WAD = 10 ** 18;

    IERC20 internal immutable DAI;

    constructor(address dai) {
        DAI = IERC20(dai);
    }

    function makerPsmSellGem(address recipient, uint256 bips, IPSM psm, IERC20Meta gemToken) internal {
        // phantom overflow can't happen here because PSM prohibits gemToken with decimals > 18
        uint256 sellAmount = (gemToken.balanceOf(address(this)) * bips).unsafeDiv(10_000);
        gemToken.safeApproveIfBelow(psm.gemJoin(), sellAmount);
        psm.sellGem(recipient, sellAmount);
    }

    function makerPsmBuyGem(address recipient, uint256 bips, IPSM psm, IERC20Meta gemToken) internal {
        // phantom overflow can't happen here because DAI has decimals = 18
        uint256 sellAmount = (DAI.balanceOf(address(this)) * bips).unsafeDiv(10_000);
        unchecked {
            uint256 feeDivisor = psm.tout() + WAD; // eg. 1.001 * 10 ** 18 with 0.1% fee [tout is in wad];
            // overflow can't happen at all because DAI is reasonable and PSM prohibits gemToken with decimals > 18
            uint256 buyAmount = (sellAmount * 10 ** uint256(gemToken.decimals())).unsafeDiv(feeDivisor);

            DAI.safeApproveIfBelow(address(psm), sellAmount);
            psm.buyGem(recipient, buyAmount);
        }
    }
}

File 10 of 24 : SafeTransferLib.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.25;

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

/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer.
/// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller.
library SafeTransferLib {
    uint32 private constant _TRANSFER_FROM_FAILED_SELECTOR = 0x7939f424; // bytes4(keccak256("TransferFromFailed()"))
    uint32 private constant _TRANSFER_FAILED_SELECTOR = 0x90b8ec18; // bytes4(keccak256("TransferFailed()"))
    uint32 private constant _APPROVE_FAILED_SELECTOR = 0x3e3f8f73; // bytes4(keccak256("ApproveFailed()"))

    /*//////////////////////////////////////////////////////////////
                             ETH OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function safeTransferETH(address payable to, uint256 amount) internal {
        assembly ("memory-safe") {
            // Transfer the ETH and store if it succeeded or not.
            if iszero(call(gas(), to, amount, 0, 0, 0, 0)) {
                let freeMemoryPointer := mload(0x40)
                returndatacopy(freeMemoryPointer, 0, returndatasize())
                revert(freeMemoryPointer, returndatasize())
            }
        }
    }

    /*//////////////////////////////////////////////////////////////
                            ERC20 OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function safeTransferFrom(IERC20 token, address from, address to, uint256 amount) internal {
        assembly ("memory-safe") {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "from" argument.
            mstore(add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
            mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.

            // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3.
            // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
            if iszero(call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)) {
                returndatacopy(freeMemoryPointer, 0, returndatasize())
                revert(freeMemoryPointer, returndatasize())
            }
            // We check that the call either returned exactly 1 (can't just be non-zero data), or had no
            // return data.
            if iszero(or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize()))) {
                mstore(0, _TRANSFER_FROM_FAILED_SELECTOR)
                revert(0x1c, 0x04)
            }
        }
    }

    function safeTransfer(IERC20 token, address to, uint256 amount) internal {
        assembly ("memory-safe") {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
            mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.

            // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
            // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
            if iszero(call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)) {
                returndatacopy(freeMemoryPointer, 0, returndatasize())
                revert(freeMemoryPointer, returndatasize())
            }
            // We check that the call either returned exactly 1 (can't just be non-zero data), or had no
            // return data.
            if iszero(or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize()))) {
                mstore(0, _TRANSFER_FAILED_SELECTOR)
                revert(0x1c, 0x04)
            }
        }
    }

    function safeApprove(IERC20 token, address to, uint256 amount) internal {
        assembly ("memory-safe") {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
            mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.

            // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
            // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
            if iszero(call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)) {
                returndatacopy(freeMemoryPointer, 0, returndatasize())
                revert(freeMemoryPointer, returndatasize())
            }
            // We check that the call either returned exactly 1 (can't just be non-zero data), or had no
            // return data.
            if iszero(or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize()))) {
                mstore(0, _APPROVE_FAILED_SELECTOR)
                revert(0x1c, 0x04)
            }
        }
    }

    function safeApproveIfBelow(IERC20 token, address spender, uint256 amount) internal {
        uint256 allowance = token.allowance(address(this), spender);
        if (allowance < amount) {
            if (allowance != 0) {
                safeApprove(token, spender, 0);
            }
            safeApprove(token, spender, type(uint256).max);
        }
    }
}

File 11 of 24 : UnsafeMath.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

library UnsafeMath {
    function unsafeInc(uint256 x) internal pure returns (uint256) {
        unchecked {
            return x + 1;
        }
    }

    function unsafeInc(int256 x) internal pure returns (int256) {
        unchecked {
            return x + 1;
        }
    }

    function unsafeNeg(int256 x) internal pure returns (int256) {
        unchecked {
            return -x;
        }
    }

    function unsafeDiv(uint256 numerator, uint256 denominator) internal pure returns (uint256 quotient) {
        assembly ("memory-safe") {
            quotient := div(numerator, denominator)
        }
    }

    function unsafeDiv(int256 numerator, int256 denominator) internal pure returns (int256 quotient) {
        assembly ("memory-safe") {
            quotient := sdiv(numerator, denominator)
        }
    }

    function unsafeMod(uint256 numerator, uint256 denominator) internal pure returns (uint256 remainder) {
        assembly ("memory-safe") {
            remainder := mod(numerator, denominator)
        }
    }

    function unsafeMod(int256 numerator, int256 denominator) internal pure returns (int256 remainder) {
        assembly ("memory-safe") {
            remainder := smod(numerator, denominator)
        }
    }

    function unsafeMulMod(uint256 a, uint256 b, uint256 m) internal pure returns (uint256 r) {
        assembly ("memory-safe") {
            r := mulmod(a, b, m)
        }
    }

    function unsafeAddMod(uint256 a, uint256 b, uint256 m) internal pure returns (uint256 r) {
        assembly ("memory-safe") {
            r := addmod(a, b, m)
        }
    }
}

File 12 of 24 : FullMath.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

import {UnsafeMath} from "../utils/UnsafeMath.sol";
import {Panic} from "../utils/Panic.sol";

/// @title Contains 512-bit math functions
/// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision
/// @dev Handles "phantom overflow" i.e., allows multiplication and division where an intermediate value overflows 256 bits
/// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv
library FullMath {
    using UnsafeMath for uint256;

    /// @notice 512-bit multiply [prod1 prod0] = a * b
    /// @param a The multiplicand
    /// @param b The multiplier
    /// @param denominator The divisor
    /// @return prod0 Least significant 256 bits of the product
    /// @return prod1 Most significant 256 bits of the product
    /// @return remainder Remainder of full-precision division
    function _mulDivSetup(uint256 a, uint256 b, uint256 denominator)
        private
        pure
        returns (uint256 prod0, uint256 prod1, uint256 remainder)
    {
        // Compute the product mod 2**256 and mod 2**256 - 1 then use the Chinese
        // Remainder Theorem to reconstruct the 512 bit result. The result is stored
        // in two 256 variables such that product = prod1 * 2**256 + prod0
        assembly ("memory-safe") {
            // Full-precision multiplication
            {
                let mm := mulmod(a, b, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
                prod0 := mul(a, b)
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }
            remainder := mulmod(a, b, denominator)
        }
    }

    /// @notice 512-bit by 256-bit division.
    /// @param prod0 Least significant 256 bits of the product
    /// @param prod1 Most significant 256 bits of the product
    /// @param denominator The divisor
    /// @param remainder Remainder of full-precision division
    /// @return The 256-bit result
    /// @dev Overflow and division by zero aren't checked and are GIGO errors
    function _mulDivInvert(uint256 prod0, uint256 prod1, uint256 denominator, uint256 remainder)
        private
        pure
        returns (uint256)
    {
        uint256 inv;
        assembly ("memory-safe") {
            // Make division exact by rounding [prod1 prod0] down to a multiple of
            // denominator
            // Subtract 256 bit number from 512 bit number
            prod1 := sub(prod1, gt(remainder, prod0))
            prod0 := sub(prod0, remainder)

            // Factor powers of two out of denominator
            {
                // Compute largest power of two divisor of denominator.
                // Always >= 1.
                let twos := and(sub(0, denominator), denominator)

                // Divide denominator by power of two
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by the factors of two
                prod0 := div(prod0, twos)
                // Shift in bits from prod1 into prod0. For this we need to flip `twos`
                // such that it is 2**256 / twos.
                // If twos is zero, then it becomes one
                twos := add(div(sub(0, twos), twos), 1)
                prod0 := or(prod0, mul(prod1, twos))
            }

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

            // Now use Newton-Raphson iteration to improve the precision.
            // Thanks to Hensel's lifting lemma, this also works in modular
            // arithmetic, doubling the correct bits in each step.
            inv := mul(inv, sub(2, mul(denominator, inv))) // inverse mod 2**8
            inv := mul(inv, sub(2, mul(denominator, inv))) // inverse mod 2**16
            inv := mul(inv, sub(2, mul(denominator, inv))) // inverse mod 2**32
            inv := mul(inv, sub(2, mul(denominator, inv))) // inverse mod 2**64
            inv := mul(inv, sub(2, mul(denominator, inv))) // inverse mod 2**128
            inv := mul(inv, sub(2, mul(denominator, inv))) // inverse mod 2**256
        }

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

    /// @notice Calculates a×b÷denominator with full precision then rounds towards 0. Throws if result overflows a uint256 or denominator == 0
    /// @param a The multiplicand
    /// @param b The multiplier
    /// @param denominator The divisor
    /// @return The 256-bit result
    function mulDiv(uint256 a, uint256 b, uint256 denominator) internal pure returns (uint256) {
        (uint256 prod0, uint256 prod1, uint256 remainder) = _mulDivSetup(a, b, denominator);
        // Make sure the result is less than 2**256.
        // Also prevents denominator == 0
        if (denominator <= prod1) {
            Panic.panic(denominator == 0 ? Panic.DIVISION_BY_ZERO : Panic.ARITHMETIC_OVERFLOW);
        }

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

    /// @notice Calculates a×b÷denominator with full precision then rounds towards 0. Overflowing a uint256 or denominator == 0 are GIGO errors
    /// @param a The multiplicand
    /// @param b The multiplier
    /// @param denominator The divisor
    /// @return The 256-bit result
    function unsafeMulDiv(uint256 a, uint256 b, uint256 denominator) internal pure returns (uint256) {
        (uint256 prod0, uint256 prod1, uint256 remainder) = _mulDivSetup(a, b, denominator);
        // Overflow and zero-division checks are skipped
        // Handle non-overflow cases, 256 by 256 division
        if (prod1 == 0) {
            return prod0.unsafeDiv(denominator);
        }
        return _mulDivInvert(prod0, prod1, denominator, remainder);
    }
}

File 13 of 24 : FreeMemory.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

abstract contract FreeMemory {
    modifier DANGEROUS_freeMemory() {
        uint256 freeMemPtr;
        assembly ("memory-safe") {
            freeMemPtr := mload(0x40)
        }
        _;
        assembly ("memory-safe") {
            mstore(0x40, freeMemPtr)
        }
    }
}

File 14 of 24 : ISettlerActions.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

import {ISignatureTransfer} from "permit2/src/interfaces/ISignatureTransfer.sol";

interface ISettlerActions {
    /// @dev Transfer funds from msg.sender Permit2.
    function PERMIT2_TRANSFER_FROM(
        address recipient,
        ISignatureTransfer.PermitTransferFrom memory permit,
        bytes memory sig
    ) external;

    /// @dev Transfer funds from metatransaction requestor into the Settler contract using Permit2. Only for use in `Settler.executeMetaTxn` where the signature is provided as calldata
    function METATXN_PERMIT2_TRANSFER_FROM(address recipient, ISignatureTransfer.PermitTransferFrom memory) external;

    /// @dev Settle an OtcOrder between maker and taker transfering funds directly between the parties
    // Post-req: Payout if recipient != taker
    function SETTLER_OTC_PERMIT2(
        address recipient,
        ISignatureTransfer.PermitTransferFrom memory makerPermit,
        address maker,
        bytes memory makerSig,
        ISignatureTransfer.PermitTransferFrom memory takerPermit,
        bytes memory takerSig
    ) external;

    /// @dev Settle an OtcOrder between maker and taker transfering funds directly between the parties for the entire amount
    function METATXN_SETTLER_OTC_PERMIT2(
        address recipient,
        ISignatureTransfer.PermitTransferFrom memory makerPermit,
        address maker,
        bytes memory makerSig,
        ISignatureTransfer.PermitTransferFrom memory takerPermit
    ) external;

    /// @dev Settle an OtcOrder between Maker and Settler. Transfering funds from the Settler contract to maker.
    /// Retaining funds in the settler contract.
    // Pre-req: Funded
    // Post-req: Payout
    function SETTLER_OTC_SELF_FUNDED(
        address recipient,
        ISignatureTransfer.PermitTransferFrom memory permit,
        address maker,
        bytes memory makerSig,
        address takerToken,
        uint256 maxTakerAmount
    ) external;

    /// @dev Trades against UniswapV3 using the contracts balance for funding
    // Pre-req: Funded
    // Post-req: Payout
    function UNISWAPV3_SWAP_EXACT_IN(address recipient, uint256 bips, uint256 amountOutMin, bytes memory path)
        external;

    /// @dev Trades against UniswapV3 using user funds via Permit2 for funding
    function UNISWAPV3_PERMIT2_SWAP_EXACT_IN(
        address recipient,
        uint256 amountIn,
        uint256 amountOutMin,
        bytes memory path,
        ISignatureTransfer.PermitTransferFrom memory permit,
        bytes memory sig
    ) external;

    function MAKER_PSM_SELL_GEM(address recipient, uint256 bips, address psm, address gemToken) external;
    function MAKER_PSM_BUY_GEM(address recipient, uint256 bips, address psm, address gemToken) external;

    /// @dev Trades against UniswapV3 using user funds via Permit2 for funding. Metatransaction variant. Signature is over all actions.
    function METATXN_UNISWAPV3_PERMIT2_SWAP_EXACT_IN(
        address recipient,
        uint256 amountIn,
        uint256 amountOutMin,
        bytes memory path,
        ISignatureTransfer.PermitTransferFrom memory permit
    ) external;

    /// @dev Trades against UniswapV2 using the contracts balance for funding
    function UNISWAPV2_SWAP(
        address recipient,
        address sellToken,
        address pool,
        uint8 swapInfo,
        uint256 bips,
        uint256 amountOutMin
    ) external;

    function POSITIVE_SLIPPAGE(address recipient, address token, uint256 expectedAmount) external;

    /// @dev Trades against a basic AMM which follows the approval, transferFrom(msg.sender) interaction
    // Pre-req: Funded
    // Post-req: Payout
    function BASIC_SELL(address pool, address sellToken, uint256 bips, uint256 offset, bytes calldata data) external;
}

File 15 of 24 : SettlerErrors.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

/// @notice Thrown when an offset is not the expected value
error InvalidOffset();

/// @notice Thrown when a validating a target contract to avoid certain types of targets
error ConfusedDeputy();

/// @notice Thrown when a target contract is invalid given the context
error InvalidTarget();

/// @notice Thrown when validating the caller against the expected caller
error InvalidSender();

/// @notice Thrown in cases when using a Trusted Forwarder / AllowanceHolder is not allowed
error ForwarderNotAllowed();

/// @notice Thrown when a signature length is not the expected length
error InvalidSignatureLen();

/// @notice Thrown when a slippage limit is exceeded
error TooMuchSlippage(address token, uint256 expected, uint256 actual);

File 16 of 24 : IEIP712.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

interface IEIP712 {
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

File 17 of 24 : AllowanceHolderContext.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

import {Context} from "../Context.sol";
import {IAllowanceHolder} from "./IAllowanceHolder.sol";

abstract contract AllowanceHolderContext is Context {
    IAllowanceHolder internal constant _ALLOWANCE_HOLDER = IAllowanceHolder(0x0000000000001fF3684f28c67538d4D072C22734);

    function _isForwarded() internal view virtual override returns (bool) {
        return super._isForwarded() || super._msgSender() == address(_ALLOWANCE_HOLDER);
    }

    function _msgSender() internal view virtual override returns (address sender) {
        sender = super._msgSender();
        if (sender == address(_ALLOWANCE_HOLDER)) {
            // ERC-2771 like usage where the _trusted_ `AllowanceHolder` has appended the appropriate
            // msg.sender to the msg data
            assembly ("memory-safe") {
                sender := shr(0x60, calldataload(sub(calldatasize(), 0x14)))
            }
        }
    }

    // this is here to avoid foot-guns and make it very explicit that we intend
    // to pass the confused deputy check in AllowanceHolder
    function balanceOf(address) external pure {
        assembly ("memory-safe") {
            mstore8(0x00, 0x00)
            revert(0x00, 0x01)
        }
    }
}

File 18 of 24 : SettlerAbstract.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

import {Permit2PaymentAbstract} from "./core/Permit2PaymentAbstract.sol";

abstract contract SettlerAbstract is Permit2PaymentAbstract {
    // Permit2 Witness for meta transactions
    string internal constant ACTIONS_AND_SLIPPAGE_TYPE =
        "ActionsAndSlippage(address buyToken,address recipient,uint256 minAmountOut,bytes[] actions)";
    bytes32 internal constant ACTIONS_AND_SLIPPAGE_TYPEHASH =
        0x7d6b6ac05bf0d3f905c044bcb7baf6b20670f84c2275870747ac3b8fa8c43e12;

    constructor() {
        assert(ACTIONS_AND_SLIPPAGE_TYPEHASH == keccak256(bytes(ACTIONS_AND_SLIPPAGE_TYPE)));
    }
}

File 19 of 24 : Revert.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

library Revert {
    function _revert(bytes memory reason) internal pure {
        assembly ("memory-safe") {
            revert(add(reason, 0x20), mload(reason))
        }
    }

    function maybeRevert(bool success, bytes memory reason) internal pure {
        if (!success) {
            _revert(reason);
        }
    }
}

File 20 of 24 : Panic.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

library Panic {
    function panic(uint256 code) internal pure {
        assembly ("memory-safe") {
            mstore(0x00, 0x4e487b71) // selector for `Panic(uint256)`
            mstore(0x20, code)
            revert(0x1c, 0x24)
        }
    }

    // https://docs.soliditylang.org/en/latest/control-structures.html#panic-via-assert-and-error-via-require
    uint8 internal constant GENERIC = 0x00;
    uint8 internal constant ASSERT_FAIL = 0x01;
    uint8 internal constant ARITHMETIC_OVERFLOW = 0x11;
    uint8 internal constant DIVISION_BY_ZERO = 0x12;
    uint8 internal constant ENUM_CAST = 0x21;
    uint8 internal constant CORRUPT_STORAGE_ARRAY = 0x22;
    uint8 internal constant POP_EMPTY_ARRAY = 0x31;
    uint8 internal constant ARRAY_OUT_OF_BOUNDS = 0x32;
    uint8 internal constant OUT_OF_MEMORY = 0x41;
    uint8 internal constant ZERO_FUNCTION_POINTER = 0x51;
}

File 21 of 24 : AddressDerivation.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

import {Panic} from "./Panic.sol";
import {UnsafeMath} from "./UnsafeMath.sol";

library AddressDerivation {
    using UnsafeMath for uint256;

    uint256 internal constant _SECP256K1_P = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F;
    uint256 internal constant _SECP256K1_N = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141;
    uint256 internal constant SECP256K1_GX = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798;
    uint256 internal constant SECP256K1_GY = 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8;

    error InvalidCurve(uint256 x, uint256 y);

    // keccak256(abi.encodePacked(ECMUL([x, y], k)))[12:]
    function deriveEOA(uint256 x, uint256 y, uint256 k) internal pure returns (address) {
        if (k == 0) {
            Panic.panic(Panic.DIVISION_BY_ZERO);
        }
        if (k >= _SECP256K1_N || x >= _SECP256K1_P || y >= _SECP256K1_P) {
            Panic.panic(Panic.ARITHMETIC_OVERFLOW);
        }

        // +/-7 are neither square nor cube mod p, so we only have to check one
        // coordinate against 0. if it is 0, then the other is too (the point at
        // infinity) or the point is invalid
        if (
            x == 0
                || y.unsafeMulMod(y, _SECP256K1_P)
                    != x.unsafeMulMod(x, _SECP256K1_P).unsafeMulMod(x, _SECP256K1_P).unsafeAddMod(7, _SECP256K1_P)
        ) {
            revert InvalidCurve(x, y);
        }

        unchecked {
            // https://ethresear.ch/t/you-can-kinda-abuse-ecrecover-to-do-ecmul-in-secp256k1-today/2384
            return ecrecover(
                bytes32(0), uint8(27 + (y & 1)), bytes32(x), bytes32(UnsafeMath.unsafeMulMod(x, k, _SECP256K1_N))
            );
        }
    }

    // keccak256(RLP([deployer, nonce]))[12:]
    function deriveContract(address deployer, uint64 nonce) internal pure returns (address result) {
        if (nonce == 0) {
            assembly ("memory-safe") {
                mstore(
                    0x00,
                    or(
                        0xd694000000000000000000000000000000000000000080,
                        shl(8, and(0xffffffffffffffffffffffffffffffffffffffff, deployer))
                    )
                )
                result := keccak256(0x09, 0x17)
            }
        } else if (nonce < 0x80) {
            assembly ("memory-safe") {
                // we don't care about dirty bits in `deployer`; they'll be overwritten later
                mstore(0x14, deployer)
                mstore(0x00, 0xd694)
                mstore8(0x34, nonce)
                result := keccak256(0x1e, 0x17)
            }
        } else {
            // compute ceil(log_256(nonce)) + 1
            uint256 nonceLength = 8;
            unchecked {
                if ((uint256(nonce) >> 32) != 0) {
                    nonceLength += 32;
                    if (nonce == type(uint64).max) {
                        Panic.panic(Panic.ARITHMETIC_OVERFLOW);
                    }
                }
                if ((uint256(nonce) >> 8) >= (1 << nonceLength)) {
                    nonceLength += 16;
                }
                if (uint256(nonce) >= (1 << nonceLength)) {
                    nonceLength += 8;
                }
                // ceil
                if ((uint256(nonce) << 8) >= (1 << nonceLength)) {
                    nonceLength += 8;
                }
                // bytes, not bits
                nonceLength >>= 3;
            }
            assembly ("memory-safe") {
                // we don't care about dirty bits in `deployer` or `nonce`. they'll be overwritten later
                mstore(nonceLength, nonce)
                mstore8(0x20, add(0x7f, nonceLength))
                mstore(0x00, deployer)
                mstore8(0x0a, add(0xd5, nonceLength))
                mstore8(0x0b, 0x94)
                result := keccak256(0x0a, add(0x16, nonceLength))
            }
        }
    }

    // keccak256(abi.encodePacked(bytes1(0xff), deployer, salt, initHash))[12:]
    function deriveDeterministicContract(address deployer, bytes32 salt, bytes32 initHash)
        internal
        pure
        returns (address result)
    {
        assembly ("memory-safe") {
            let ptr := mload(0x40)
            // we don't care about dirty bits in `deployer`; they'll be overwritten later
            mstore(ptr, deployer)
            mstore8(add(ptr, 0x0b), 0xff)
            mstore(add(ptr, 0x20), salt)
            mstore(add(ptr, 0x40), initHash)
            result := keccak256(add(ptr, 0x0b), 0x55)
        }
    }
}

File 22 of 24 : Context.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

abstract contract AbstractContext {
    function _msgSender() internal view virtual returns (address);

    function _msgData() internal view virtual returns (bytes calldata);

    function _isForwarded() internal view virtual returns (bool);
}

abstract contract Context is AbstractContext {
    function _msgSender() internal view virtual override returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual override returns (bytes calldata) {
        return msg.data;
    }

    function _isForwarded() internal view virtual override returns (bool) {
        return false;
    }
}

File 23 of 24 : IAllowanceHolder.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

interface IAllowanceHolder {
    /// @notice Executes against `target` with the `data` payload. Prior to execution, token permits
    ///         are temporarily stored for the duration of the transaction. These permits can be
    ///         consumed by the `operator` during the execution
    /// @notice `operator` consumes the funds during its operations by calling back into
    ///         `AllowanceHolder` with `transferFrom`, consuming a token permit.
    /// @dev Neither `exec` nor `transferFrom` check that `token` contains code.
    /// @dev msg.sender is forwarded to target appended to the msg data (similar to ERC-2771)
    /// @param operator An address which is allowed to consume the token permits
    /// @param token The ERC20 token the caller has authorised to be consumed
    /// @param amount The quantity of `token` the caller has authorised to be consumed
    /// @param target A contract to execute operations with `data`
    /// @param data The data to forward to `target`
    /// @return result The returndata from calling `target` with `data`
    /// @notice If calling `target` with `data` reverts, the revert is propagated
    function exec(address operator, address token, uint256 amount, address payable target, bytes calldata data)
        external
        payable
        returns (bytes memory result);

    /// @notice The counterpart to `exec` which allows for the consumption of token permits later
    ///         during execution
    /// @dev *DOES NOT* check that `token` contains code. This function vacuously succeeds if
    ///      `token` is empty.
    /// @dev can only be called by the `operator` previously registered in `exec`
    /// @param token The ERC20 token to transfer
    /// @param owner The owner of tokens to transfer
    /// @param recipient The destination/beneficiary of the ERC20 `transferFrom`
    /// @param amount The quantity of `token` to transfer`
    /// @return true
    function transferFrom(address token, address owner, address recipient, uint256 amount) external returns (bool);
}

File 24 of 24 : Permit2PaymentAbstract.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

import {AbstractContext} from "../Context.sol";

import {ISignatureTransfer} from "permit2/src/interfaces/ISignatureTransfer.sol";

abstract contract Permit2PaymentAbstract is AbstractContext {
    string internal constant TOKEN_PERMISSIONS_TYPE = "TokenPermissions(address token,uint256 amount)";

    function isRestrictedTarget(address) internal view virtual returns (bool);

    function _permitToTransferDetails(ISignatureTransfer.PermitTransferFrom memory permit, address recipient)
        internal
        pure
        virtual
        returns (ISignatureTransfer.SignatureTransferDetails memory transferDetails, address token, uint256 amount);

    function _transferFrom(
        ISignatureTransfer.PermitTransferFrom memory permit,
        ISignatureTransfer.SignatureTransferDetails memory transferDetails,
        address from,
        bytes32 witness,
        string memory witnessTypeString,
        bytes memory sig,
        bool isForwarded
    ) internal virtual;

    function _transferFrom(
        ISignatureTransfer.PermitTransferFrom memory permit,
        ISignatureTransfer.SignatureTransferDetails memory transferDetails,
        address from,
        bytes32 witness,
        string memory witnessTypeString,
        bytes memory sig
    ) internal virtual;

    function _transferFrom(
        ISignatureTransfer.PermitTransferFrom memory permit,
        ISignatureTransfer.SignatureTransferDetails memory transferDetails,
        address from,
        bytes memory sig,
        bool isForwarded
    ) internal virtual;

    function _transferFrom(
        ISignatureTransfer.PermitTransferFrom memory permit,
        ISignatureTransfer.SignatureTransferDetails memory transferDetails,
        address from,
        bytes memory sig
    ) internal virtual;

    function _setOperatorAndCall(address payable target, uint256 value, bytes memory data)
        internal
        virtual
        returns (bytes memory);

    function _setOperatorAndCall(address target, bytes memory data) internal virtual returns (bytes memory);

    modifier metaTx(address msgSender, bytes32 witness) virtual;
}

Settings
{
  "remappings": [
    "solmate/=lib/solmate/",
    "permit2/=lib/permit2/",
    "forge-std/=lib/forge-std/src/",
    "forge-gas-snapshot/=lib/forge-gas-snapshot/src/",
    "ds-test/=lib/forge-std/lib/ds-test/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 1000000,
    "details": {
      "constantOptimizer": true,
      "yul": true
    }
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "none",
    "appendCBOR": false
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": true,
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"uniFactory","type":"address"},{"internalType":"bytes32","name":"poolInitCodeHash","type":"bytes32"},{"internalType":"address","name":"dai","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"i","type":"uint256"},{"internalType":"bytes4","name":"action","type":"bytes4"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"ActionInvalid","type":"error"},{"inputs":[],"name":"ConfusedDeputy","type":"error"},{"inputs":[],"name":"ForwarderNotAllowed","type":"error"},{"inputs":[],"name":"InvalidOffset","type":"error"},{"inputs":[],"name":"InvalidSignatureLen","type":"error"},{"inputs":[],"name":"InvalidTarget","type":"error"},{"inputs":[{"internalType":"address","name":"oldOperator","type":"address"}],"name":"OperatorNotSpent","type":"error"},{"inputs":[{"internalType":"address","name":"oldOperator","type":"address"}],"name":"ReentrantCallback","type":"error"},{"inputs":[{"internalType":"bytes32","name":"oldWitness","type":"bytes32"}],"name":"ReentrantMetatransaction","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"actual","type":"uint256"}],"name":"TooMuchSlippage","type":"error"},{"inputs":[{"internalType":"bytes32","name":"oldWitness","type":"bytes32"}],"name":"WitnessNotSpent","type":"error"},{"inputs":[],"name":"ZeroSwapAmount","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"actions","type":"bytes[]"},{"components":[{"internalType":"address","name":"buyToken","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"}],"internalType":"struct Settler.AllowedSlippage","name":"slippage","type":"tuple"}],"name":"execute","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"actions","type":"bytes[]"},{"components":[{"internalType":"address","name":"buyToken","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"}],"internalType":"struct Settler.AllowedSlippage","name":"slippage","type":"tuple"},{"internalType":"address","name":"msgSender","type":"address"},{"internalType":"bytes","name":"sig","type":"bytes"}],"name":"executeMetaTxn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"int256","name":"amount0Delta","type":"int256"},{"internalType":"int256","name":"amount1Delta","type":"int256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"uniswapV3SwapCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60e06040908082523461025c576060816157968038038091610021828561028f565b83398101031261025c57610034816102b2565b9060209161020661004a858585015194016102b2565b936100f7605b875161005b81610260565b8181527f6e416d6f756e744f75742c62797465735b5d20616374696f6e732900000000006060858301927f416374696f6e73416e64536c697070616765286164647265737320627579546f84527f6b656e2c6164647265737320726563697069656e742c75696e74323536206d698c8201520152207f7d6b6ac05bf0d3f905c044bcb7baf6b20670f84c2275870747ac3b8fa8c43e121461034b565b61012f6101026102c6565b8281519101207f7d806873084f389a66fd0315dead7adaad8ae6e8b6cf9fb0d3db61e5a91c3ffa1461034b565b85519061013b82610260565b604b82526101dc818301917f4f74634f7264657228436f6e73696465726174696f6e206d616b6572436f6e7383527f696465726174696f6e2c436f6e73696465726174696f6e2074616b6572436f6e898501526a73696465726174696f6e2960a81b60608501526101aa6102c6565b92818a5194859282840197518091895e8301908282015f8152815193849201905e015f8382015203808452018261028f565b5190207f4efcac36537dd5721596376472101aec5ff380b23b286c66cdfe70a509c0cef31461034b565b60805260a0526001600160a01b031660c0525161542f9081610367823960805181613eba015260a05181613eed015260c051818181610e6301528181610f6c01528181611e6301528181612f6001526130690152f35b5f80fd5b608081019081106001600160401b0382111761027b57604052565b634e487b7160e01b5f52604160045260245ffd5b601f909101601f19168101906001600160401b0382119082101761027b57604052565b51906001600160a01b038216820361025c57565b604051906102d382610260565b605882527f626f6f6c207061727469616c46696c6c416c6c6f7765642900000000000000006060837f436f6e73696465726174696f6e286164647265737320746f6b656e2c75696e7460208201527f32353620616d6f756e742c6164647265737320636f756e74657270617274792c60408201520152565b1561035257565b634e487b7160e01b5f52600160045260245ffdfe6080604052600436101561001a575b3615610018575f80fd5b005b5f3560e01c806370a0823114613714578063dd304e4314612299578063e4b11b291461018c5763fa461e330361000e573461015e5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261015e5760043560243560443567ffffffffffffffff811161015e5761009f9036906004016137bc565b909283358060601c600b8601359573ffffffffffffffffffffffffffffffffffffffff6100d588601f8401359560481c85613e6d565b1633036101625784603f1161015e57603f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc191019401945f84135f1461012057506100189550613f58565b9250505f8213156101345761001894613f58565b60046040517f19f49342000000000000000000000000000000000000000000000000000000008152fd5b5f80fd5b60046040517fe758b8d5000000000000000000000000000000000000000000000000000000008152fd5b60807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261015e5767ffffffffffffffff60043581811161015e576101d790369060040161378b565b9060607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc36011261015e578161130c575b90600190610214613828565b915b81811061022557610018613c99565b610230818386613a0e565b6040519193927fffffffff00000000000000000000000000000000000000000000000000000000167f828bf4f4000000000000000000000000000000000000000000000000000000008103610305575083019260c08185031261015e576102968161376a565b6102a38560208401613bde565b9060a0830135928a841161015e576102e373ffffffffffffffffffffffffffffffffffffffff6102db6001996102fc978d9501613bc0565b931684614051565b50506d1ff3684f28c67538d4d072c22734331493614703565b60405201610216565b7f362094eb000000000000000000000000000000000000000000000000000000008103610618575083016101208482031261015e576103438461376a565b6103508260208701613bde565b61035c60a0870161376a565b60c08701358b811161015e578994610375918901613bc0565b9173ffffffffffffffffffffffffffffffffffffffff61039760e08a0161376a565b985f60206040516103a781613ad7565b828152015261046c8a836103df816040519a6103c28c613abb565b5f8c525f60208d01525f60408d0152600160608d01521687614051565b9b9196168a528a60208b015281881660408b0152816040519361040185613abb565b1683526101008501356020840152166040820152600160608201527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0019081517f7d806873084f389a66fd0315dead7adaad8ae6e8b6cf9fb0d3db61e5a91c3ffa835260a083209252565b99604051917f70a0823100000000000000000000000000000000000000000000000000000000835230600484015260208360248173ffffffffffffffffffffffffffffffffffffffff86165afa92831561060d575f936105c3575b50948b6105a99560019d9995610534866105b19d9b966fffffffffffffffffffffffffffffffff9b6105599992610100820135106105b6575b610515610100602087019201358483516153a0565b905273ffffffffffffffffffffffffffffffffffffffff87169061433e565b73ffffffffffffffffffffffffffffffffffffffff6105516140f0565b941691615084565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0019081517f7d806873084f389a66fd0315dead7adaad8ae6e8b6cf9fb0d3db61e5a91c3ffa835260a083209252565b911691615146565b6102fc565b6101008101359250610500565b949896919b9793959092506020853d602011610605575b816105e760209383613b0f565b8101031261015e579351969a9597929690959394929390918b6104c7565b3d91506105da565b6040513d5f823e3d90fd5b7fc102e15900000000000000000000000000000000000000000000000000000000810361079a5750830160808482031261015e576106558461376a565b936020916060820135908a821161015e57610671918301613bc0565b94602483875181890151907fffffffffffffffffffffffffffffffffffffffff00000000000000000000000091828116916014808210610786575b5050509050604051928380927f70a0823100000000000000000000000000000000000000000000000000000000825230600483015260601c5afa90811561060d575f91610750575b509060019661271061070f85948761074a9897013590614641565b0490604080519561071f87613af3565b603f8752369087013773ffffffffffffffffffffffffffffffffffffffff6040309501359316614c02565b506102fc565b93809392915084813d831161077f575b61076a8183613b0f565b8101031261015e5792519192909160016106f4565b503d610760565b849293500360031b1b1616808e80806106ac565b929391927fee45a2a4000000000000000000000000000000000000000000000000000000008103610c1457508160c0918101031261015e576107db8161376a565b906107e86020820161376a565b916107f56040830161376a565b90606083013560ff8116900361015e575f936080840135610b72575b604051919085610b0b575b630902f1ac5f5260405f6004601c73ffffffffffffffffffffffffffffffffffffffff88165afa15610b025760403d1061015e5760016060860135818116821460051b8051602090911851909390929091811c811614881517610a95575b506103e86103e5910281880201918702020491606073ffffffffffffffffffffffffffffffffffffffff601c83019363022c0d9f84526080808501525f60a0850152856020600180868c0135161460051b860101525f601c600180868c0135161460051b60040160201886010152169101525f8060a4838273ffffffffffffffffffffffffffffffffffffffff88165af115610a8d575060a08301351161092757505050906001916102fc565b602073ffffffffffffffffffffffffffffffffffffffff91600180606086013516145f14610a24576004604051809481937fd21220a7000000000000000000000000000000000000000000000000000000008352165afa92831561060d5760a0936109f1925f916109f5575b505b6040519485947f97a6f3b90000000000000000000000000000000000000000000000000000000086520135906004850160409194939273ffffffffffffffffffffffffffffffffffffffff606083019616825260208201520152565b0390fd5b610a17915060203d602011610a1d575b610a0f8183613b0f565b810190614654565b85610993565b503d610a05565b6004604051809481937f0dfe1681000000000000000000000000000000000000000000000000000000008352165afa92831561060d5760a0936109f1925f91610a6e575b50610995565b610a87915060203d602011610a1d57610a0f8183613b0f565b85610a68565b3d5f823e3d90fd5b73ffffffffffffffffffffffffffffffffffffffff9197505f6020916370a0823182528388168352601c6024948592165afa15610af95760203d1061015e575f5190878210610ae95750869003958d61087a565b634e487b715f526011602052601cfd5b833d5f823e3d90fd5b823d5f823e3d90fd5b63a9059cbb835273ffffffffffffffffffffffffffffffffffffffff8416602084015285604084015260205f6044601c86018273ffffffffffffffffffffffffffffffffffffffff86165af115610b025760015f511460203d1015163d151761081c575f80fd5b9093506040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260208160248173ffffffffffffffffffffffffffffffffffffffff86165afa801561060d575f90610be0575b6127109150608085013502049390610811565b506020813d602011610c0c575b81610bfa60209383613b0f565b8101031261015e576127109051610bcd565b3d9150610bed565b9293927feb53ad58000000000000000000000000000000000000000000000000000000008103610de0575090610c4c91810190613c49565b94929173ffffffffffffffffffffffffffffffffffffffff8096166040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526020928382602481865afa801561060d5789925f91610dab575b5061271091610cbb91614641565b04931691604051917f01664f660000000000000000000000000000000000000000000000000000000083528183600481875afa90811561060d57610d099386935f93610d8c575b505061520c565b803b1561015e576040517f959912760000000000000000000000000000000000000000000000000000000081529590921673ffffffffffffffffffffffffffffffffffffffff16600486015260248501525f9084908183816044810103925af192831561060d57600193610d7d57506102fc565b610d8690613a7a565b8761074a565b610da3929350803d10610a1d57610a0f8183613b0f565b908e80610d02565b809350858092503d8311610dd9575b610dc48183613b0f565b8101031261015e579051889190612710610cad565b503d610dba565b7f69b2a24e0000000000000000000000000000000000000000000000000000000081036110dc575090610e1591810190613c49565b91604095939195517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260208160248173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa90811561060d575f916110a8575b5061271091610ea191614641565b0494604051927ffae036d500000000000000000000000000000000000000000000000000000000845260208460048173ffffffffffffffffffffffffffffffffffffffff86165afa93841561060d575f94611073575b5092602073ffffffffffffffffffffffffffffffffffffffff946004604051809781937f313ce567000000000000000000000000000000000000000000000000000000008352165afa93841561060d575f94611035575b50610f908773ffffffffffffffffffffffffffffffffffffffff84167f000000000000000000000000000000000000000000000000000000000000000061520c565b73ffffffffffffffffffffffffffffffffffffffff82163b1561015e576040517f8d7ef9bb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9384166004820152670de0b6b3a76400009190910160ff94909416600a0a969096029290920460248601525f91859160449183918591165af192831561060d57600193610d7d57506102fc565b9093506020813d60201161106b575b8161105160209383613b0f565b8101031261015e575160ff8116810361015e57928b610f4e565b3d9150611044565b93506020843d6020116110a0575b8161108e60209383613b0f565b8101031261015e579251926020610ef7565b3d9150611081565b90506020813d6020116110d4575b816110c360209383613b0f565b8101031261015e5751612710610e93565b3d91506110b6565b9193917f1cc408a900000000000000000000000000000000000000000000000000000000810361116f5750830160a08482031261015e5761111c8461376a565b936111296020820161376a565b906080810135958a871161015e576111486105b1946001988401613bc0565b9273ffffffffffffffffffffffffffffffffffffffff6040606085013594013592166143f7565b7fc876d21d0000000000000000000000000000000000000000000000000000000081036112c65750836060918101031261015e576111ac8361376a565b60209060406111bc83870161376a565b9501359173ffffffffffffffffffffffffffffffffffffffff8092169186169573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee87145f14611224575050600194504791808311611211575b5050506102fc565b61121c9203906143b9565b878080611209565b91909283602497604051988980927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa93841561060d575f94611295575b5060019650808411611281575b505050506102fc565b61128c93039161433e565b87808080611278565b90935086813d83116112bf575b6112ac8183613b0f565b8101031261015e5760019551928b61126b565b503d6112a2565b6109f191859184957f3c74eed6000000000000000000000000000000000000000000000000000000008652600486015260248501526060604485015260648401916137ea565b7fffffffff000000000000000000000000000000000000000000000000000000006113378383613991565b929091167fd864fda100000000000000000000000000000000000000000000000000000000810361140c5750604051918101906101808183031261015e5761137e8161376a565b61138b8360208401613bde565b9161139860a0820161376a565b9160c082013589811161015e57856113b1918401613bc0565b906113bf8660e08501613bde565b92610160810135968b881161015e57611404976113dc9201613bc0565b9473ffffffffffffffffffffffffffffffffffffffff806113fb613828565b961692166141da565b604052610208565b7ff9306b150000000000000000000000000000000000000000000000000000000081036115275750604051918101906101208183031261015e5761144f8161376a565b90606081013587811161015e5783611468918301613bc0565b906114768460808301613bde565b9261010082013589811161015e5761151e95611493918401613bc0565b60406114a76114a28351613f1d565b614002565b95602081518051605f8a01520151607f8801526020810151609f880152015160bf86015260016d1ff3684f28c67538d4d072c2273433141660df86015260208151910160ff86015e6114f7613828565b9273ffffffffffffffffffffffffffffffffffffffff602060408501359401359216614c02565b50604052610208565b91611530613828565b9082604051947f828bf4f40000000000000000000000000000000000000000000000000000000081145f146115b75750019060c08383031261015e576115758361376a565b906115838360208601613bde565b9260a085013589811161015e576102db6102e39273ffffffffffffffffffffffffffffffffffffffff926114049801613bc0565b7f362094eb000000000000000000000000000000000000000000000000000000008103611830575001916101208184031261015e576115f58161376a565b6116028460208401613bde565b9361160f60a0840161376a565b9060c0840135908a821161015e57611628918501613bc0565b9073ffffffffffffffffffffffffffffffffffffffff602461164c60e0870161376a565b5f602060405161165b81613ad7565b828152015261168e836040519761167189613abb565b5f89525f60208a01525f60408a0152600160608a0152168a614051565b98919416875287602088015273ffffffffffffffffffffffffffffffffffffffff85166040880152602061175f73ffffffffffffffffffffffffffffffffffffffff84169a73ffffffffffffffffffffffffffffffffffffffff604051916116f583613abb565b8d835261010086013585840152166040820152600160608201527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0019081517f7d806873084f389a66fd0315dead7adaad8ae6e8b6cf9fb0d3db61e5a91c3ffa835260a083209252565b99604051948580927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa92831561060d575f936117ee575b506117e99961055994610534856fffffffffffffffffffffffffffffffff9a98958d956105a99b9892610100820135106105b657610515610100602087019201358483516153a0565b611404565b959250929593906020863d602011611828575b8161180e60209383613b0f565b8101031261015e57945193959194909391926117e96117a0565b3d9150611801565b919250907fc102e15900000000000000000000000000000000000000000000000000000000810361196e5750019060808183031261015e576118718161376a565b90602091606082013588811161015e5760249461188f918401613bc0565b83815181830151907fffffffffffffffffffffffffffffffffffffffff000000000000000000000000918281169160148110611959575b50509050604051968780927f70a0823100000000000000000000000000000000000000000000000000000000825230600483015260601c5afa94851561060d575f95611928575b5061271061070f611922968686013590614641565b50611404565b94508385813d8311611952575b61193f8183613b0f565b8101031261015e5793519361271061190d565b503d611935565b8391925060140360031b1b1616808c806118c6565b7fee45a2a4000000000000000000000000000000000000000000000000000000008103611c4d575060c0918101031261015e576119aa8161376a565b906119b76020820161376a565b916119c46040830161376a565b90606083013560ff8116900361015e575f936080840135611bad575b60405185611b46575b630902f1ac5f5260405f6004601c73ffffffffffffffffffffffffffffffffffffffff88165afa15610a8d5760403d1061015e576001806060870135161460051b9182519083602018519060018060608a0135811c1614891517611adb575b5060609173ffffffffffffffffffffffffffffffffffffffff916103e86103e59102818b0201918a020204945f601c8086019663022c0d9f87526080808801528260a0880152886020828901015260040160201886010152169101525f8060a4838273ffffffffffffffffffffffffffffffffffffffff88165af115610a8d575060a08301351161092757505050611404565b60209198506024601c73ffffffffffffffffffffffffffffffffffffffff5f936370a082318552818b168652165afa15611b3d5760203d1061015e575f51878110611b2b57879003966060611a48565b634e487b715f5260116020526024601cfd5b503d5f823e3d90fd5b63a9059cbb815273ffffffffffffffffffffffffffffffffffffffff8416602082015285604082015260205f6044601c84018273ffffffffffffffffffffffffffffffffffffffff87165af115610a8d5760015f511460203d1015163d15176119e9575f80fd5b93506040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260208160248173ffffffffffffffffffffffffffffffffffffffff89165afa801561060d575f90611c19575b612710915060808501350204936119e0565b506020813d602011611c45575b81611c3360209383613b0f565b8101031261015e576127109051611c07565b3d9150611c26565b90507feb53ad58000000000000000000000000000000000000000000000000000000008103611e12575090611c8491810190613c49565b929173ffffffffffffffffffffffffffffffffffffffff8094166040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526020928382602481865afa801561060d5787925f91611ddd575b5061271091611cf291614641565b04931691604051917f01664f660000000000000000000000000000000000000000000000000000000083528183600481875afa90811561060d57611d3f9386935f93611dbe57505061520c565b803b1561015e576040517f959912760000000000000000000000000000000000000000000000000000000081529390921673ffffffffffffffffffffffffffffffffffffffff16600484015260248301525f9082908183816044810103925af1801561060d57611daf5750611404565b611db890613a7a565b84611922565b611dd5929350803d10610a1d57610a0f8183613b0f565b908c80610d02565b809350858092503d8311611e0b575b611df68183613b0f565b8101031261015e579051869190612710611ce4565b503d611dec565b7f69b2a24e00000000000000000000000000000000000000000000000000000000810361209d575090611e4791810190613c49565b9173ffffffffffffffffffffffffffffffffffffffff939193917f0000000000000000000000000000000000000000000000000000000000000000916040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260209182826024818989165afa801561060d5786925f91612068575b5061271091611ed991614641565b04961692604051957ffae036d50000000000000000000000000000000000000000000000000000000087528287600481885afa96871561060d575f97612033575b5090828693926004604051809981937f313ce567000000000000000000000000000000000000000000000000000000008352165afa95861561060d5788925f97611ff4575b50509084611f6c9261520c565b823b1561015e576040517f8d7ef9bb000000000000000000000000000000000000000000000000000000008152911673ffffffffffffffffffffffffffffffffffffffff166004820152670de0b6b3a76400009390930160ff92909216600a0a93909302046024820152905f908290604490829084905af1801561060d57611daf5750611404565b809297508193503d831161202c575b61200d8183613b0f565b8101031261015e575160ff8116810361015e5793869084611f6c611f5f565b503d612003565b92809291975083813d8311612061575b61204d8183613b0f565b8101031261015e5791519590919082611f1a565b503d612043565b809350848092503d8311612096575b6120818183613b0f565b8101031261015e579051859190612710611ecb565b503d612077565b7f1cc408a9000000000000000000000000000000000000000000000000000000008103612104575081019060a08183031261015e576120db8161376a565b906120e86020820161376a565b91608082013588811161015e576117e994611148918401613bc0565b7fc876d21d0000000000000000000000000000000000000000000000000000000081036122545750816060918101031261015e576121418161376a565b604061214f6020840161376a565b9201359073ffffffffffffffffffffffffffffffffffffffff8091169083169273eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee84145f146121b45750479250908083116121a1575b505050611404565b6121ac9203906143b9565b848080612199565b916020602494604051958680927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa93841561060d575f94612220575b5080841161220c575b50505050611404565b61221793039161433e565b84808080612203565b9093506020813d60201161224c575b8161223c60209383613b0f565b8101031261015e575192886121fa565b3d915061222f565b7f3c74eed60000000000000000000000000000000000000000000000000000000084525f600485015260248401526060604484015282916109f19160648401916137ea565b3461015e5760c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261015e5760043567ffffffffffffffff811161015e576122e890369060040161378b565b60607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc36011261015e5773ffffffffffffffffffffffffffffffffffffffff608435166084350361015e5760a43567ffffffffffffffff811161015e576123539036906004016137bc565b906040518481905b8560051b870181106136f657505060a0908460051b9020604051907f7d6b6ac05bf0d3f905c044bcb7baf6b20670f84c2275870747ac3b8fa8c43e1282526060602460208401376080820152207f1643bf8e9fdaef48c4abf5a998de359be44a235ac7aebfbc05485e093720deaa5c806136c557507f1643bf8e9fdaef48c4abf5a998de359be44a235ac7aebfbc05485e093720deaa5d60843573ffffffffffffffffffffffffffffffffffffffff167ffc7be34027b4062d13b31d75182f37b703b5ad960f0e73236593535549bb277d5d61243d612438613828565b61386c565b826133d9575b505060015b8181106124b957612457613c99565b61245f613921565b7f1643bf8e9fdaef48c4abf5a998de359be44a235ac7aebfbc05485e093720deaa5c8061248857005b602490604051907fe25527c20000000000000000000000000000000000000000000000000000000082526004820152fd5b6124c4818385613a0e565b9291907fffffffff0000000000000000000000000000000000000000000000000000000060405192167f828bf4f40000000000000000000000000000000000000000000000000000000081145f146125ae575060c081858101031261015e5761252c8161376a565b61253b85830160208401613bde565b9067ffffffffffffffff60a08401351161015e5761258773ffffffffffffffffffffffffffffffffffffffff61257f856001996125a597019060a081013501613bc0565b921683614051565b5050916d1ff3684f28c67538d4d072c2273433149260843591614703565b60405201612448565b9093907f362094eb000000000000000000000000000000000000000000000000000000008103612846575061012084828101031261015e576125ef8461376a565b6125fe82860160208701613bde565b9161260b60a0870161376a565b9060c087013567ffffffffffffffff811161015e5761262e918801908801613bc0565b9061263b60e0880161376a565b935f602060405161264b81613ad7565b828152015273ffffffffffffffffffffffffffffffffffffffff6024612695826040519761267889613abb565b5f89525f60208a01525f60408a0152600160608a01521684614051565b98919316875287602088015273ffffffffffffffffffffffffffffffffffffffff8516604088015273ffffffffffffffffffffffffffffffffffffffff81169a60206127698d604051906126e882613abb565b81526101008401358382015273ffffffffffffffffffffffffffffffffffffffff608435166040820152600160608201527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0019081517f7d806873084f389a66fd0315dead7adaad8ae6e8b6cf9fb0d3db61e5a91c3ffa835260a083209252565b9c604051948580927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa92831561060d575f936127fc575b50948b6105a99560019d9995610534866127f79d9b966fffffffffffffffffffffffffffffffff9b6105599992610100820135106105b657610515610100602087019201358483516153a0565b6125a5565b949896919b9793959092506020853d60201161283e575b8161282060209383613b0f565b8101031261015e579351969a9597929690959394929390918b6127aa565b3d9150612813565b9093907fc102e1590000000000000000000000000000000000000000000000000000000081036129d75750608081858101031261015e576128868161376a565b93606082013567ffffffffffffffff811161015e576128a9918301908301613bc0565b9060246020835181850151907fffffffffffffffffffffffffffffffffffffffff000000000000000000000000918281169160148082106129c3575b5050509050604051928380927f70a0823100000000000000000000000000000000000000000000000000000000825230600483015260601c5afa90811561060d575f9161298a575b50906001956127106129486129849594602085013590614641565b046040519361295685613af3565b603f8552604036602087013773ffffffffffffffffffffffffffffffffffffffff6040309501359316614c02565b506125a5565b929190506020833d6020116129bb575b816129a760209383613b0f565b8101031261015e579151909190600161292d565b3d915061299a565b849293500360031b1b1616808b80806128e5565b7fee45a2a400000000000000000000000000000000000000000000000000000000819592939495145f14612cbf57508160c0918101031261015e57612a1b8161376a565b90612a286020820161376a565b91612a356040830161376a565b90606083013560ff8116900361015e575f936080840135612c1d575b604051919085612bb6575b630902f1ac5f5260405f6004601c73ffffffffffffffffffffffffffffffffffffffff88165afa15610b025760403d1061015e5760016060860135818116821460051b8051602090911851909390929091811c811614881517612b67575b506103e86103e5910281880201918702020491606073ffffffffffffffffffffffffffffffffffffffff601c83019363022c0d9f84526080808501525f60a0850152856020600180868c0135161460051b860101525f601c600180868c0135161460051b60040160201886010152169101525f8060a4838273ffffffffffffffffffffffffffffffffffffffff88165af115610a8d575060a08301351161092757505050906001916125a5565b60209197506024601c73ffffffffffffffffffffffffffffffffffffffff5f936370a082318552818a168652165afa15610b025760203d1061015e575f51868110611b2b57869003958b612aba565b63a9059cbb835273ffffffffffffffffffffffffffffffffffffffff8416602084015285604084015260205f6044601c86018273ffffffffffffffffffffffffffffffffffffffff86165af115610b025760015f511460203d1015163d1517612a5c575f80fd5b9093506040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260208160248173ffffffffffffffffffffffffffffffffffffffff86165afa801561060d575f90612c8b575b6127109150608085013502049390612a51565b506020813d602011612cb7575b81612ca560209383613b0f565b8101031261015e576127109051612c78565b3d9150612c98565b9293927feb53ad58000000000000000000000000000000000000000000000000000000008103612edd575090612cf791810190613c49565b909492916040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260208160248173ffffffffffffffffffffffffffffffffffffffff87165afa90811561060d575f91612ea9575b5061271091612d6291614641565b04906040517f01664f6600000000000000000000000000000000000000000000000000000000815260208160048173ffffffffffffffffffffffffffffffffffffffff8b165afa801561060d57612dd89284925f92612e72575b5073ffffffffffffffffffffffffffffffffffffffff1661520c565b73ffffffffffffffffffffffffffffffffffffffff85163b1561015e576040517f9599127600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff92831660048201526024810191909152935f91859160449183918591165af192831561060d57600193612e6357506125a5565b612e6c90613a7a565b85612984565b73ffffffffffffffffffffffffffffffffffffffff919250612ea29060203d602011610a1d57610a0f8183613b0f565b9190612dbc565b90506020813d602011612ed5575b81612ec460209383613b0f565b8101031261015e5751612710612d54565b3d9150612eb7565b7f69b2a24e0000000000000000000000000000000000000000000000000000000081036131d9575090612f1291810190613c49565b91604095939195517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260208160248173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa90811561060d575f916131a5575b5061271091612f9e91614641565b0494604051927ffae036d500000000000000000000000000000000000000000000000000000000845260208460048173ffffffffffffffffffffffffffffffffffffffff86165afa93841561060d575f94613170575b5092602073ffffffffffffffffffffffffffffffffffffffff946004604051809781937f313ce567000000000000000000000000000000000000000000000000000000008352165afa93841561060d575f94613132575b5061308d8773ffffffffffffffffffffffffffffffffffffffff84167f000000000000000000000000000000000000000000000000000000000000000061520c565b73ffffffffffffffffffffffffffffffffffffffff82163b1561015e576040517f8d7ef9bb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9384166004820152670de0b6b3a76400009190910160ff94909416600a0a969096029290920460248601525f91859160449183918591165af192831561060d57600193612e6357506125a5565b9093506020813d602011613168575b8161314e60209383613b0f565b8101031261015e575160ff8116810361015e57928961304b565b3d9150613141565b93506020843d60201161319d575b8161318b60209383613b0f565b8101031261015e579251926020612ff4565b3d915061317e565b90506020813d6020116131d1575b816131c060209383613b0f565b8101031261015e5751612710612f90565b3d91506131b3565b9193917f1cc408a900000000000000000000000000000000000000000000000000000000810361324d5750830160a08482031261015e576132198461376a565b936132266020820161376a565b9060808101359567ffffffffffffffff871161015e576111486127f7946001988401613bc0565b7fc876d21d0000000000000000000000000000000000000000000000000000000081036112c65750836060918101031261015e5761328a8361376a565b926132976020820161376a565b73ffffffffffffffffffffffffffffffffffffffff8116949073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee86036133155750600194504791604081013583116132e6575b5050506125a5565b61330d92604073ffffffffffffffffffffffffffffffffffffffff920135900391166143b9565b8580806132de565b6020602496604051978880927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa92831561060d575f936133a4575b6001965060408101358411613373575b505050506125a5565b61339b93604073ffffffffffffffffffffffffffffffffffffffff920135900392169061433e565b8580808061336a565b92506020863d6020116133d1575b816133bf60209383613b0f565b8101031261015e57600195519261335a565b3d91506133b2565b7fffffffff000000000000000000000000000000000000000000000000000000006134048486613991565b929091167fe2ed3db40000000000000000000000000000000000000000000000000000000081036134d857506040519361016082848101031261015e5761344a8261376a565b9261345a81840160208501613bde565b9361346760a0850161376a565b9360c08101359667ffffffffffffffff881161015e576134a28260e06134986134cd9b886134aa9701908401613bc0565b9682019101613bde565b943691613b8a565b9473ffffffffffffffffffffffffffffffffffffffff80608435961692166141da565b6040525b8280612443565b909391907fedef505000000000000000000000000000000000000000000000000000000000810361358257506040519360a081838101031261015e5761357a9361355473ffffffffffffffffffffffffffffffffffffffff61354c84602061354261355e9761376a565b9782019101613bde565b941684614051565b5050933691613b8a565b906d1ff3684f28c67538d4d072c2273433149260843591614703565b6040526134d1565b7fbac152c500000000000000000000000000000000000000000000000000000000810361367c57506040519361010081838101031261015e576135c48161376a565b606082013567ffffffffffffffff811161015e57613673956135fd6135f161360593878701908701613bc0565b95850160808601613bde565b953691613b8a565b60406136146114a28351613f1d565b95602081518051605f8a01520151607f8801526020810151609f880152015160bf8601525f60df86015260208151910160ff86015e6084359273ffffffffffffffffffffffffffffffffffffffff602060408501359401359216614c02565b506040526134d1565b6109f1856040519384937f3c74eed60000000000000000000000000000000000000000000000000000000085525f600486015260248501526060604485015260648401916137ea565b602490604051907f9936cbab0000000000000000000000000000000000000000000000000000000082526004820152fd5b6020813588018035918291018437822082526020918201910161235b565b3461015e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261015e5760043573ffffffffffffffffffffffffffffffffffffffff81160361015e575f805360015ffd5b359073ffffffffffffffffffffffffffffffffffffffff8216820361015e57565b9181601f8401121561015e5782359167ffffffffffffffff831161015e576020808501948460051b01011161015e57565b9181601f8401121561015e5782359167ffffffffffffffff831161015e576020838186019501011161015e57565b601f82602094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe093818652868601375f8582860101520116010190565b33906d1ff3684f28c67538d4d072c22734331461384157565b367fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec013560601c9150565b73ffffffffffffffffffffffffffffffffffffffff90817ffc7be34027b4062d13b31d75182f37b703b5ad960f0e73236593535549bb277d5c1682821614610162577e9355806b743562f351db2e3726091207f49fa1cdccd5c65a7d4860ce3abbe99180835c1680151580613917575b6138e6575016905d565b602490604051907f77f944250000000000000000000000000000000000000000000000000000000082526004820152fd5b50803314156138dc565b73ffffffffffffffffffffffffffffffffffffffff7e9355806b743562f351db2e3726091207f49fa1cdccd5c65a7d4860ce3abbe95c16806139605750565b602490604051907f08a303650000000000000000000000000000000000000000000000000000000082526004820152fd5b80358101929160051b018210613a09573682101561015e5781359160208101602084830101818110613a0957361061015e57600484106139f7577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc602491359401910191565b634e487b715f5260326020526024601cfd5b611b2b565b8091939260051b013581019260051b018210613a09573682101561015e5781359160208101602084830101818110613a0957361061015e57600484106139f7577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc602491359401910191565b67ffffffffffffffff8111613a8e57604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6080810190811067ffffffffffffffff821117613a8e57604052565b6040810190811067ffffffffffffffff821117613a8e57604052565b6060810190811067ffffffffffffffff821117613a8e57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117613a8e57604052565b67ffffffffffffffff8111613a8e57601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b929192613b9682613b50565b91613ba46040519384613b0f565b82948184528183011161015e578281602093845f960137010152565b9080601f8301121561015e57816020613bdb93359101613b8a565b90565b80929103916080831261015e57604051906060820182811067ffffffffffffffff821117613a8e5780604052604083951261015e5760409181613c22606093613ad7565b613c2b8261376a565b81526020820135608086015284528281013560208501520135910152565b919082608091031261015e57613c5e8261376a565b9160208101359173ffffffffffffffffffffffffffffffffffffffff6040830135818116810361015e579260600135908116810361015e5790565b73ffffffffffffffffffffffffffffffffffffffff602435818116929183820361015e576044359081169081810361015e57606435948515801590613e64575b613ce6575b505050509050565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8103613d795750504791848310613d225750613d189293506143b9565b805f808080613cde565b6040517f97a6f3b900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9190911660048201526024810185905260448101839052606490fd5b909150604051927f70a08231000000000000000000000000000000000000000000000000000000008452306004850152602084602481855afa93841561060d575f94613e30575b50858410613dd95750613dd493945061433e565b613d18565b6040517f97a6f3b900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9190911660048201526024810186905260448101849052606490fd5b9093506020813d602011613e5c575b81613e4c60209383613b0f565b8101031261015e5751925f613dc0565b3d9150613e3f565b50801515613cd9565b73ffffffffffffffffffffffffffffffffffffffff92605592909184811685841680821015613f14575050915b6040519285165f52841660205262ffffff1660405260605f2090806040527f00000000000000000000000000000000000000000000000000000000000000008152600b81019160ff8353602082015260407f0000000000000000000000000000000000000000000000000000000000000000910152201690565b93509050613e9a565b60df01908160df11613f2b57565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b91929073ffffffffffffffffffffffffffffffffffffffff81163003613f88575050613f869250339061433e565b565b9150915082820160a08382031261015e57613fa39083613bde565b90608083013592831515840361015e578460a01161015e57613ffc613f8695613fcc3386614051565b50509260a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff603693019101613b8a565b92614703565b9061400c82613b50565b6140196040519182613b0f565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06140478294613b50565b0190602036910137565b604051929161405f84613ad7565b60208401915f83528473ffffffffffffffffffffffffffffffffffffffff809316905260208151015180935251511691565b6040519061409e82613af3565b602e82527f696e7432353620616d6f756e74290000000000000000000000000000000000006040837f546f6b656e5065726d697373696f6e73286164647265737320746f6b656e2c7560208201520152565b6040516140fc81613abb565b60588152613bdb603c60208301927f436f6e73696465726174696f6e286164647265737320746f6b656e2c75696e7484527f32353620616d6f756e742c6164647265737320636f756e74657270617274792c60408201527f626f6f6c207061727469616c46696c6c416c6c6f77656429000000000000000060608201526020614183614091565b6040519586937f436f6e73696465726174696f6e20636f6e73696465726174696f6e2900000000848601525180918686015e8301908482015f8152815193849201905e015f8382015203601c810184520182613b0f565b6141e8909693959682614051565b969190956141f68582614051565b6040989198519061420682613abb565b73ffffffffffffffffffffffffffffffffffffffff998a16825260208201528b891660408201525f60608201527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00180517f7d806873084f389a66fd0315dead7adaad8ae6e8b6cf9fb0d3db61e5a91c3ffa825260a0822091529a336d1ff3684f28c67538d4d072c22734149261429c94614703565b87846142a66140f0565b926142b095615084565b81604051936142be85613abb565b168352602083018490521660408201525f60608201527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00180517f7d806873084f389a66fd0315dead7adaad8ae6e8b6cf9fb0d3db61e5a91c3ffa825260a082209152906fffffffffffffffffffffffffffffffff1690613f8692615146565b60446020925f809373ffffffffffffffffffffffffffffffffffffffff966040519788947fa9059cbb00000000000000000000000000000000000000000000000000000000865216600485015260248401525af115610a8d57503d15601f3d1160015f51141617156143ac57565b6390b8ec185f526004601cfd5b5f80809381935af11561060d57565b3d156143f2573d906143d982613b50565b916143e76040519384613b0f565b82523d5f602084013e565b606090565b90929173ffffffffffffffffffffffffffffffffffffffff808316946e22d473030f116ddee9f6b43ac78ba38614801561462a575b610162575f91811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81036145335750505061445c9047615189565b938051155f146144b757505061448d575f80809381935af161447c6143c8565b90156144855750565b602081519101fd5b60046040517f01da1572000000000000000000000000000000000000000000000000000000008152fd5b90939260208301808411613f2b578251106139f757835f9460208695850101525b602083519301915af16144e96143c8565b90156144855751159081614529575b506144ff57565b60046040517f82d5d76a000000000000000000000000000000000000000000000000000000008152fd5b90503b155f6144f8565b9091949281979497155f146145525750505061448d575f9283926144d8565b604096959496939293517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526020918282602481875afa801561060d575f906145fb575b6145a79250615189565b92818101808211613f2b578851106145ea57865f9896949293838a9997958c948a010152036145d9575b5050506144d8565b6145e29261520c565b5f80876145d1565b603282634e487b715f52526024601cfd5b508282813d8311614623575b6146118183613b0f565b8101031261015e576145a7915161459d565b503d614607565b506d1ff3684f28c67538d4d072c22734861461442c565b81810292918115918404141715613f2b57565b9081602091031261015e575173ffffffffffffffffffffffffffffffffffffffff8116810361015e5790565b60406060916146b08482516020809173ffffffffffffffffffffffffffffffffffffffff81511684520151910152565b6020810151828501520151910152565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602080948051918291828752018686015e5f8582860101520116010190565b90919273ffffffffffffffffffffffffffffffffffffffff948580614726613828565b1695169485141580614b6b575b610162575f7f1643bf8e9fdaef48c4abf5a998de359be44a235ac7aebfbc05485e093720deaa90815c9182614b3a575b50816148fc57505015614842575161481857836020915151169382511691015191604051937f15dacbea00000000000000000000000000000000000000000000000000000000855260048501526024840152604483015260648201526020816084815f6d1ff3684f28c67538d4d072c227345af1801561060d576147e45750565b6020813d602011614810575b816147fd60209383613b0f565b8101031261015e57518015150361015e57565b3d91506147f0565b60046040517fc321526c000000000000000000000000000000000000000000000000000000008152fd5b9350916e22d473030f116ddee9f6b43ac78ba390813b1561015e575f80946148e26148ca976148a294604051998a98899788967f30f28b7a0000000000000000000000000000000000000000000000000000000088526004880190614680565b805173ffffffffffffffffffffffffffffffffffffffff1660848701526020015160a4860152565b60c484015261010060e48401526101048301906146c0565b03925af1801561060d576148f35750565b613f8690613a7a565b909691959294939291168103610162577f7070616765290000000000000000000000000000000000000000000000000000604095614a1a6046886020815161494381613abb565b605b81528181017f416374696f6e73416e64536c697070616765286164647265737320627579546f81527f6b656e2c6164647265737320726563697069656e742c75696e74323536206d69848301527f6e416d6f756e744f75742c62797465735b5d20616374696f6e7329000000000060608301526149c0614091565b9184519889957f416374696f6e73416e64536c69707061676520616374696f6e73416e64536c69868801528601525180918686015e8301908482015f8152815193849201905e015f83820152036026810185520183613b0f565b614b11576e22d473030f116ddee9f6b43ac78ba392833b1561015e57614af55f96614ac48894614aa69b614a7e978c519d8e9b8c9a8b997f137c29fe000000000000000000000000000000000000000000000000000000008b5260048b0190614680565b805173ffffffffffffffffffffffffffffffffffffffff1660848a01526020015160a4890152565b60c487015260e48601526101406101048601526101448501906146c0565b907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc848303016101248501526146c0565b03925af1908115614b0857506148f35750565b513d5f823e3d90fd5b600486517f1c500e5c000000000000000000000000000000000000000000000000000000008152fd5b90505f7ffc7be34027b4062d13b31d75182f37b703b5ad960f0e73236593535549bb277d9181835c935d5d5f614763565b50857e9355806b743562f351db2e3726091207f49fa1cdccd5c65a7d4860ce3abbe9805c9081614ba0575b5016331415614733565b5f905d5f614b96565b919360a093613bdb969573ffffffffffffffffffffffffffffffffffffffff809416855215156020850152604084015216606082015281608082015201906146c0565b919082604091031261015e576020825192015190565b92939095917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8111611b2b575b865190602b82106139f757601488015160178901519088602b8b015192829684859873ffffffffffffffffffffffffffffffffffffffff871673ffffffffffffffffffffffffffffffffffffffff8716101561507b575b614c91828583613e6d565b9385519284603f880152602b87015260178601526014850152835273ffffffffffffffffffffffffffffffffffffffff309116145f14614ef4579073ffffffffffffffffffffffffffffffffffffffff83928a86602b8a115f14614ee657838092505f91614d4e30975b838316848b16108514614ecc576401000276a45b60409d8e9a8b519c8d9b8c9a8b987f128acb08000000000000000000000000000000000000000000000000000000008a52169116109060048701614ba9565b0393165af1908115614ec2575f945f92614e78575b505073ffffffffffffffffffffffffffffffffffffffff809194935b1691161015614e7157505b7f80000000000000000000000000000000000000000000000000000000000000008114613f2b575f03915f8312611b2b57602b83921115614e0957505030909560178151106139f757807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe96017925101828201520195603f8652614c2f565b9493509550509250808410614e1c575050565b6040517f97a6f3b900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff929092166004830152602482015260448101839052606490fd5b9050614d8a565b73ffffffffffffffffffffffffffffffffffffffff95508592509081614eb292903d10614ebb575b614eaa8183613b0f565b810190614bec565b94909491614d63565b503d614ea0565b84513d5f823e3d90fd5b73fffd8963efd1fc6a506488495d951d5263988d25614d0f565b835f91614d4e829497614cfb565b9293919273ffffffffffffffffffffffffffffffffffffffff16919050602b8511156150745730915b73ffffffffffffffffffffffffffffffffffffffff851673ffffffffffffffffffffffffffffffffffffffff8516105f14615059576401000276a4925b60405180918d602096878401967f128acb0800000000000000000000000000000000000000000000000000000000885273ffffffffffffffffffffffffffffffffffffffff8b1673ffffffffffffffffffffffffffffffffffffffff8b16106024860194614fc795614ba9565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018252614ff79082613b0f565b6150008261386c565b515a925f8094938194f1906150136143c8565b91156150535761504b73ffffffffffffffffffffffffffffffffffffffff949392859261503e613921565b8082518301019101614bec565b949093614d7f565b81519101fd5b73fffd8963efd1fc6a506488495d951d5263988d2592614f5a565b8791614f1d565b50508385614c86565b91909294936e22d473030f116ddee9f6b43ac78ba392833b1561015e576148e25f96614ac488946151279a73ffffffffffffffffffffffffffffffffffffffff6150ff986040519d8e9c8d9b8c9a7f137c29fe000000000000000000000000000000000000000000000000000000008c5260048c0190614680565b805173ffffffffffffffffffffffffffffffffffffffff1660848b01526020015160a48a0152565b1660c487015260e48601526101406101048601526101448501906146c0565b9190917f4efcac36537dd5721596376472101aec5ff380b23b286c66cdfe70a509c0cef35f526020526040519160405260605f20916040526010525f5260305fa0565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff828209828202918280831092039180830391612710958691099282861115611b2b5714615206577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e919350828211900360fc1b910360041c170290565b50500490565b9173ffffffffffffffffffffffffffffffffffffffff9182916040519384927fdd62ed3e0000000000000000000000000000000000000000000000000000000084523060048501521692836024840152826044602096879389165afa91821561060d575f92615371575b508110615284575b50505050565b615312575b60445f91826040519586927f095ea7b300000000000000000000000000000000000000000000000000000000845260048401527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60248401525af115610a8d57503d15601f3d1160015f5114161715615305575f80808061527e565b633e3f8f735f526004601cfd5b6040517f095ea7b30000000000000000000000000000000000000000000000000000000081528160048201525f6024820152825f60448382885af115610a8d57503d15601f3d1160015f5114161761528957633e3f8f735f526004601cfd5b9091508381813d8311615399575b6153898183613b0f565b8101031261015e5751905f615276565b503d61537f565b917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82840981838502938480841093039509908085146154275782805f0316809304600280826003021880830282030280830282030280830282030280830282030280830282030280920290030294600184805f0304019185841191030302920304170290565b505091500490560000000000000000000000001f98431c8ad98523631ae4a59f267346ea31f984e34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b540000000000000000000000006b175474e89094c44da98b954eedeac495271d0f

Deployed Bytecode

0x6080604052600436101561001a575b3615610018575f80fd5b005b5f3560e01c806370a0823114613714578063dd304e4314612299578063e4b11b291461018c5763fa461e330361000e573461015e5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261015e5760043560243560443567ffffffffffffffff811161015e5761009f9036906004016137bc565b909283358060601c600b8601359573ffffffffffffffffffffffffffffffffffffffff6100d588601f8401359560481c85613e6d565b1633036101625784603f1161015e57603f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc191019401945f84135f1461012057506100189550613f58565b9250505f8213156101345761001894613f58565b60046040517f19f49342000000000000000000000000000000000000000000000000000000008152fd5b5f80fd5b60046040517fe758b8d5000000000000000000000000000000000000000000000000000000008152fd5b60807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261015e5767ffffffffffffffff60043581811161015e576101d790369060040161378b565b9060607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc36011261015e578161130c575b90600190610214613828565b915b81811061022557610018613c99565b610230818386613a0e565b6040519193927fffffffff00000000000000000000000000000000000000000000000000000000167f828bf4f4000000000000000000000000000000000000000000000000000000008103610305575083019260c08185031261015e576102968161376a565b6102a38560208401613bde565b9060a0830135928a841161015e576102e373ffffffffffffffffffffffffffffffffffffffff6102db6001996102fc978d9501613bc0565b931684614051565b50506d1ff3684f28c67538d4d072c22734331493614703565b60405201610216565b7f362094eb000000000000000000000000000000000000000000000000000000008103610618575083016101208482031261015e576103438461376a565b6103508260208701613bde565b61035c60a0870161376a565b60c08701358b811161015e578994610375918901613bc0565b9173ffffffffffffffffffffffffffffffffffffffff61039760e08a0161376a565b985f60206040516103a781613ad7565b828152015261046c8a836103df816040519a6103c28c613abb565b5f8c525f60208d01525f60408d0152600160608d01521687614051565b9b9196168a528a60208b015281881660408b0152816040519361040185613abb565b1683526101008501356020840152166040820152600160608201527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0019081517f7d806873084f389a66fd0315dead7adaad8ae6e8b6cf9fb0d3db61e5a91c3ffa835260a083209252565b99604051917f70a0823100000000000000000000000000000000000000000000000000000000835230600484015260208360248173ffffffffffffffffffffffffffffffffffffffff86165afa92831561060d575f936105c3575b50948b6105a99560019d9995610534866105b19d9b966fffffffffffffffffffffffffffffffff9b6105599992610100820135106105b6575b610515610100602087019201358483516153a0565b905273ffffffffffffffffffffffffffffffffffffffff87169061433e565b73ffffffffffffffffffffffffffffffffffffffff6105516140f0565b941691615084565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0019081517f7d806873084f389a66fd0315dead7adaad8ae6e8b6cf9fb0d3db61e5a91c3ffa835260a083209252565b911691615146565b6102fc565b6101008101359250610500565b949896919b9793959092506020853d602011610605575b816105e760209383613b0f565b8101031261015e579351969a9597929690959394929390918b6104c7565b3d91506105da565b6040513d5f823e3d90fd5b7fc102e15900000000000000000000000000000000000000000000000000000000810361079a5750830160808482031261015e576106558461376a565b936020916060820135908a821161015e57610671918301613bc0565b94602483875181890151907fffffffffffffffffffffffffffffffffffffffff00000000000000000000000091828116916014808210610786575b5050509050604051928380927f70a0823100000000000000000000000000000000000000000000000000000000825230600483015260601c5afa90811561060d575f91610750575b509060019661271061070f85948761074a9897013590614641565b0490604080519561071f87613af3565b603f8752369087013773ffffffffffffffffffffffffffffffffffffffff6040309501359316614c02565b506102fc565b93809392915084813d831161077f575b61076a8183613b0f565b8101031261015e5792519192909160016106f4565b503d610760565b849293500360031b1b1616808e80806106ac565b929391927fee45a2a4000000000000000000000000000000000000000000000000000000008103610c1457508160c0918101031261015e576107db8161376a565b906107e86020820161376a565b916107f56040830161376a565b90606083013560ff8116900361015e575f936080840135610b72575b604051919085610b0b575b630902f1ac5f5260405f6004601c73ffffffffffffffffffffffffffffffffffffffff88165afa15610b025760403d1061015e5760016060860135818116821460051b8051602090911851909390929091811c811614881517610a95575b506103e86103e5910281880201918702020491606073ffffffffffffffffffffffffffffffffffffffff601c83019363022c0d9f84526080808501525f60a0850152856020600180868c0135161460051b860101525f601c600180868c0135161460051b60040160201886010152169101525f8060a4838273ffffffffffffffffffffffffffffffffffffffff88165af115610a8d575060a08301351161092757505050906001916102fc565b602073ffffffffffffffffffffffffffffffffffffffff91600180606086013516145f14610a24576004604051809481937fd21220a7000000000000000000000000000000000000000000000000000000008352165afa92831561060d5760a0936109f1925f916109f5575b505b6040519485947f97a6f3b90000000000000000000000000000000000000000000000000000000086520135906004850160409194939273ffffffffffffffffffffffffffffffffffffffff606083019616825260208201520152565b0390fd5b610a17915060203d602011610a1d575b610a0f8183613b0f565b810190614654565b85610993565b503d610a05565b6004604051809481937f0dfe1681000000000000000000000000000000000000000000000000000000008352165afa92831561060d5760a0936109f1925f91610a6e575b50610995565b610a87915060203d602011610a1d57610a0f8183613b0f565b85610a68565b3d5f823e3d90fd5b73ffffffffffffffffffffffffffffffffffffffff9197505f6020916370a0823182528388168352601c6024948592165afa15610af95760203d1061015e575f5190878210610ae95750869003958d61087a565b634e487b715f526011602052601cfd5b833d5f823e3d90fd5b823d5f823e3d90fd5b63a9059cbb835273ffffffffffffffffffffffffffffffffffffffff8416602084015285604084015260205f6044601c86018273ffffffffffffffffffffffffffffffffffffffff86165af115610b025760015f511460203d1015163d151761081c575f80fd5b9093506040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260208160248173ffffffffffffffffffffffffffffffffffffffff86165afa801561060d575f90610be0575b6127109150608085013502049390610811565b506020813d602011610c0c575b81610bfa60209383613b0f565b8101031261015e576127109051610bcd565b3d9150610bed565b9293927feb53ad58000000000000000000000000000000000000000000000000000000008103610de0575090610c4c91810190613c49565b94929173ffffffffffffffffffffffffffffffffffffffff8096166040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526020928382602481865afa801561060d5789925f91610dab575b5061271091610cbb91614641565b04931691604051917f01664f660000000000000000000000000000000000000000000000000000000083528183600481875afa90811561060d57610d099386935f93610d8c575b505061520c565b803b1561015e576040517f959912760000000000000000000000000000000000000000000000000000000081529590921673ffffffffffffffffffffffffffffffffffffffff16600486015260248501525f9084908183816044810103925af192831561060d57600193610d7d57506102fc565b610d8690613a7a565b8761074a565b610da3929350803d10610a1d57610a0f8183613b0f565b908e80610d02565b809350858092503d8311610dd9575b610dc48183613b0f565b8101031261015e579051889190612710610cad565b503d610dba565b7f69b2a24e0000000000000000000000000000000000000000000000000000000081036110dc575090610e1591810190613c49565b91604095939195517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260208160248173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f165afa90811561060d575f916110a8575b5061271091610ea191614641565b0494604051927ffae036d500000000000000000000000000000000000000000000000000000000845260208460048173ffffffffffffffffffffffffffffffffffffffff86165afa93841561060d575f94611073575b5092602073ffffffffffffffffffffffffffffffffffffffff946004604051809781937f313ce567000000000000000000000000000000000000000000000000000000008352165afa93841561060d575f94611035575b50610f908773ffffffffffffffffffffffffffffffffffffffff84167f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f61520c565b73ffffffffffffffffffffffffffffffffffffffff82163b1561015e576040517f8d7ef9bb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9384166004820152670de0b6b3a76400009190910160ff94909416600a0a969096029290920460248601525f91859160449183918591165af192831561060d57600193610d7d57506102fc565b9093506020813d60201161106b575b8161105160209383613b0f565b8101031261015e575160ff8116810361015e57928b610f4e565b3d9150611044565b93506020843d6020116110a0575b8161108e60209383613b0f565b8101031261015e579251926020610ef7565b3d9150611081565b90506020813d6020116110d4575b816110c360209383613b0f565b8101031261015e5751612710610e93565b3d91506110b6565b9193917f1cc408a900000000000000000000000000000000000000000000000000000000810361116f5750830160a08482031261015e5761111c8461376a565b936111296020820161376a565b906080810135958a871161015e576111486105b1946001988401613bc0565b9273ffffffffffffffffffffffffffffffffffffffff6040606085013594013592166143f7565b7fc876d21d0000000000000000000000000000000000000000000000000000000081036112c65750836060918101031261015e576111ac8361376a565b60209060406111bc83870161376a565b9501359173ffffffffffffffffffffffffffffffffffffffff8092169186169573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee87145f14611224575050600194504791808311611211575b5050506102fc565b61121c9203906143b9565b878080611209565b91909283602497604051988980927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa93841561060d575f94611295575b5060019650808411611281575b505050506102fc565b61128c93039161433e565b87808080611278565b90935086813d83116112bf575b6112ac8183613b0f565b8101031261015e5760019551928b61126b565b503d6112a2565b6109f191859184957f3c74eed6000000000000000000000000000000000000000000000000000000008652600486015260248501526060604485015260648401916137ea565b7fffffffff000000000000000000000000000000000000000000000000000000006113378383613991565b929091167fd864fda100000000000000000000000000000000000000000000000000000000810361140c5750604051918101906101808183031261015e5761137e8161376a565b61138b8360208401613bde565b9161139860a0820161376a565b9160c082013589811161015e57856113b1918401613bc0565b906113bf8660e08501613bde565b92610160810135968b881161015e57611404976113dc9201613bc0565b9473ffffffffffffffffffffffffffffffffffffffff806113fb613828565b961692166141da565b604052610208565b7ff9306b150000000000000000000000000000000000000000000000000000000081036115275750604051918101906101208183031261015e5761144f8161376a565b90606081013587811161015e5783611468918301613bc0565b906114768460808301613bde565b9261010082013589811161015e5761151e95611493918401613bc0565b60406114a76114a28351613f1d565b614002565b95602081518051605f8a01520151607f8801526020810151609f880152015160bf86015260016d1ff3684f28c67538d4d072c2273433141660df86015260208151910160ff86015e6114f7613828565b9273ffffffffffffffffffffffffffffffffffffffff602060408501359401359216614c02565b50604052610208565b91611530613828565b9082604051947f828bf4f40000000000000000000000000000000000000000000000000000000081145f146115b75750019060c08383031261015e576115758361376a565b906115838360208601613bde565b9260a085013589811161015e576102db6102e39273ffffffffffffffffffffffffffffffffffffffff926114049801613bc0565b7f362094eb000000000000000000000000000000000000000000000000000000008103611830575001916101208184031261015e576115f58161376a565b6116028460208401613bde565b9361160f60a0840161376a565b9060c0840135908a821161015e57611628918501613bc0565b9073ffffffffffffffffffffffffffffffffffffffff602461164c60e0870161376a565b5f602060405161165b81613ad7565b828152015261168e836040519761167189613abb565b5f89525f60208a01525f60408a0152600160608a0152168a614051565b98919416875287602088015273ffffffffffffffffffffffffffffffffffffffff85166040880152602061175f73ffffffffffffffffffffffffffffffffffffffff84169a73ffffffffffffffffffffffffffffffffffffffff604051916116f583613abb565b8d835261010086013585840152166040820152600160608201527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0019081517f7d806873084f389a66fd0315dead7adaad8ae6e8b6cf9fb0d3db61e5a91c3ffa835260a083209252565b99604051948580927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa92831561060d575f936117ee575b506117e99961055994610534856fffffffffffffffffffffffffffffffff9a98958d956105a99b9892610100820135106105b657610515610100602087019201358483516153a0565b611404565b959250929593906020863d602011611828575b8161180e60209383613b0f565b8101031261015e57945193959194909391926117e96117a0565b3d9150611801565b919250907fc102e15900000000000000000000000000000000000000000000000000000000810361196e5750019060808183031261015e576118718161376a565b90602091606082013588811161015e5760249461188f918401613bc0565b83815181830151907fffffffffffffffffffffffffffffffffffffffff000000000000000000000000918281169160148110611959575b50509050604051968780927f70a0823100000000000000000000000000000000000000000000000000000000825230600483015260601c5afa94851561060d575f95611928575b5061271061070f611922968686013590614641565b50611404565b94508385813d8311611952575b61193f8183613b0f565b8101031261015e5793519361271061190d565b503d611935565b8391925060140360031b1b1616808c806118c6565b7fee45a2a4000000000000000000000000000000000000000000000000000000008103611c4d575060c0918101031261015e576119aa8161376a565b906119b76020820161376a565b916119c46040830161376a565b90606083013560ff8116900361015e575f936080840135611bad575b60405185611b46575b630902f1ac5f5260405f6004601c73ffffffffffffffffffffffffffffffffffffffff88165afa15610a8d5760403d1061015e576001806060870135161460051b9182519083602018519060018060608a0135811c1614891517611adb575b5060609173ffffffffffffffffffffffffffffffffffffffff916103e86103e59102818b0201918a020204945f601c8086019663022c0d9f87526080808801528260a0880152886020828901015260040160201886010152169101525f8060a4838273ffffffffffffffffffffffffffffffffffffffff88165af115610a8d575060a08301351161092757505050611404565b60209198506024601c73ffffffffffffffffffffffffffffffffffffffff5f936370a082318552818b168652165afa15611b3d5760203d1061015e575f51878110611b2b57879003966060611a48565b634e487b715f5260116020526024601cfd5b503d5f823e3d90fd5b63a9059cbb815273ffffffffffffffffffffffffffffffffffffffff8416602082015285604082015260205f6044601c84018273ffffffffffffffffffffffffffffffffffffffff87165af115610a8d5760015f511460203d1015163d15176119e9575f80fd5b93506040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260208160248173ffffffffffffffffffffffffffffffffffffffff89165afa801561060d575f90611c19575b612710915060808501350204936119e0565b506020813d602011611c45575b81611c3360209383613b0f565b8101031261015e576127109051611c07565b3d9150611c26565b90507feb53ad58000000000000000000000000000000000000000000000000000000008103611e12575090611c8491810190613c49565b929173ffffffffffffffffffffffffffffffffffffffff8094166040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526020928382602481865afa801561060d5787925f91611ddd575b5061271091611cf291614641565b04931691604051917f01664f660000000000000000000000000000000000000000000000000000000083528183600481875afa90811561060d57611d3f9386935f93611dbe57505061520c565b803b1561015e576040517f959912760000000000000000000000000000000000000000000000000000000081529390921673ffffffffffffffffffffffffffffffffffffffff16600484015260248301525f9082908183816044810103925af1801561060d57611daf5750611404565b611db890613a7a565b84611922565b611dd5929350803d10610a1d57610a0f8183613b0f565b908c80610d02565b809350858092503d8311611e0b575b611df68183613b0f565b8101031261015e579051869190612710611ce4565b503d611dec565b7f69b2a24e00000000000000000000000000000000000000000000000000000000810361209d575090611e4791810190613c49565b9173ffffffffffffffffffffffffffffffffffffffff939193917f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f916040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260209182826024818989165afa801561060d5786925f91612068575b5061271091611ed991614641565b04961692604051957ffae036d50000000000000000000000000000000000000000000000000000000087528287600481885afa96871561060d575f97612033575b5090828693926004604051809981937f313ce567000000000000000000000000000000000000000000000000000000008352165afa95861561060d5788925f97611ff4575b50509084611f6c9261520c565b823b1561015e576040517f8d7ef9bb000000000000000000000000000000000000000000000000000000008152911673ffffffffffffffffffffffffffffffffffffffff166004820152670de0b6b3a76400009390930160ff92909216600a0a93909302046024820152905f908290604490829084905af1801561060d57611daf5750611404565b809297508193503d831161202c575b61200d8183613b0f565b8101031261015e575160ff8116810361015e5793869084611f6c611f5f565b503d612003565b92809291975083813d8311612061575b61204d8183613b0f565b8101031261015e5791519590919082611f1a565b503d612043565b809350848092503d8311612096575b6120818183613b0f565b8101031261015e579051859190612710611ecb565b503d612077565b7f1cc408a9000000000000000000000000000000000000000000000000000000008103612104575081019060a08183031261015e576120db8161376a565b906120e86020820161376a565b91608082013588811161015e576117e994611148918401613bc0565b7fc876d21d0000000000000000000000000000000000000000000000000000000081036122545750816060918101031261015e576121418161376a565b604061214f6020840161376a565b9201359073ffffffffffffffffffffffffffffffffffffffff8091169083169273eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee84145f146121b45750479250908083116121a1575b505050611404565b6121ac9203906143b9565b848080612199565b916020602494604051958680927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa93841561060d575f94612220575b5080841161220c575b50505050611404565b61221793039161433e565b84808080612203565b9093506020813d60201161224c575b8161223c60209383613b0f565b8101031261015e575192886121fa565b3d915061222f565b7f3c74eed60000000000000000000000000000000000000000000000000000000084525f600485015260248401526060604484015282916109f19160648401916137ea565b3461015e5760c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261015e5760043567ffffffffffffffff811161015e576122e890369060040161378b565b60607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc36011261015e5773ffffffffffffffffffffffffffffffffffffffff608435166084350361015e5760a43567ffffffffffffffff811161015e576123539036906004016137bc565b906040518481905b8560051b870181106136f657505060a0908460051b9020604051907f7d6b6ac05bf0d3f905c044bcb7baf6b20670f84c2275870747ac3b8fa8c43e1282526060602460208401376080820152207f1643bf8e9fdaef48c4abf5a998de359be44a235ac7aebfbc05485e093720deaa5c806136c557507f1643bf8e9fdaef48c4abf5a998de359be44a235ac7aebfbc05485e093720deaa5d60843573ffffffffffffffffffffffffffffffffffffffff167ffc7be34027b4062d13b31d75182f37b703b5ad960f0e73236593535549bb277d5d61243d612438613828565b61386c565b826133d9575b505060015b8181106124b957612457613c99565b61245f613921565b7f1643bf8e9fdaef48c4abf5a998de359be44a235ac7aebfbc05485e093720deaa5c8061248857005b602490604051907fe25527c20000000000000000000000000000000000000000000000000000000082526004820152fd5b6124c4818385613a0e565b9291907fffffffff0000000000000000000000000000000000000000000000000000000060405192167f828bf4f40000000000000000000000000000000000000000000000000000000081145f146125ae575060c081858101031261015e5761252c8161376a565b61253b85830160208401613bde565b9067ffffffffffffffff60a08401351161015e5761258773ffffffffffffffffffffffffffffffffffffffff61257f856001996125a597019060a081013501613bc0565b921683614051565b5050916d1ff3684f28c67538d4d072c2273433149260843591614703565b60405201612448565b9093907f362094eb000000000000000000000000000000000000000000000000000000008103612846575061012084828101031261015e576125ef8461376a565b6125fe82860160208701613bde565b9161260b60a0870161376a565b9060c087013567ffffffffffffffff811161015e5761262e918801908801613bc0565b9061263b60e0880161376a565b935f602060405161264b81613ad7565b828152015273ffffffffffffffffffffffffffffffffffffffff6024612695826040519761267889613abb565b5f89525f60208a01525f60408a0152600160608a01521684614051565b98919316875287602088015273ffffffffffffffffffffffffffffffffffffffff8516604088015273ffffffffffffffffffffffffffffffffffffffff81169a60206127698d604051906126e882613abb565b81526101008401358382015273ffffffffffffffffffffffffffffffffffffffff608435166040820152600160608201527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0019081517f7d806873084f389a66fd0315dead7adaad8ae6e8b6cf9fb0d3db61e5a91c3ffa835260a083209252565b9c604051948580927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa92831561060d575f936127fc575b50948b6105a99560019d9995610534866127f79d9b966fffffffffffffffffffffffffffffffff9b6105599992610100820135106105b657610515610100602087019201358483516153a0565b6125a5565b949896919b9793959092506020853d60201161283e575b8161282060209383613b0f565b8101031261015e579351969a9597929690959394929390918b6127aa565b3d9150612813565b9093907fc102e1590000000000000000000000000000000000000000000000000000000081036129d75750608081858101031261015e576128868161376a565b93606082013567ffffffffffffffff811161015e576128a9918301908301613bc0565b9060246020835181850151907fffffffffffffffffffffffffffffffffffffffff000000000000000000000000918281169160148082106129c3575b5050509050604051928380927f70a0823100000000000000000000000000000000000000000000000000000000825230600483015260601c5afa90811561060d575f9161298a575b50906001956127106129486129849594602085013590614641565b046040519361295685613af3565b603f8552604036602087013773ffffffffffffffffffffffffffffffffffffffff6040309501359316614c02565b506125a5565b929190506020833d6020116129bb575b816129a760209383613b0f565b8101031261015e579151909190600161292d565b3d915061299a565b849293500360031b1b1616808b80806128e5565b7fee45a2a400000000000000000000000000000000000000000000000000000000819592939495145f14612cbf57508160c0918101031261015e57612a1b8161376a565b90612a286020820161376a565b91612a356040830161376a565b90606083013560ff8116900361015e575f936080840135612c1d575b604051919085612bb6575b630902f1ac5f5260405f6004601c73ffffffffffffffffffffffffffffffffffffffff88165afa15610b025760403d1061015e5760016060860135818116821460051b8051602090911851909390929091811c811614881517612b67575b506103e86103e5910281880201918702020491606073ffffffffffffffffffffffffffffffffffffffff601c83019363022c0d9f84526080808501525f60a0850152856020600180868c0135161460051b860101525f601c600180868c0135161460051b60040160201886010152169101525f8060a4838273ffffffffffffffffffffffffffffffffffffffff88165af115610a8d575060a08301351161092757505050906001916125a5565b60209197506024601c73ffffffffffffffffffffffffffffffffffffffff5f936370a082318552818a168652165afa15610b025760203d1061015e575f51868110611b2b57869003958b612aba565b63a9059cbb835273ffffffffffffffffffffffffffffffffffffffff8416602084015285604084015260205f6044601c86018273ffffffffffffffffffffffffffffffffffffffff86165af115610b025760015f511460203d1015163d1517612a5c575f80fd5b9093506040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260208160248173ffffffffffffffffffffffffffffffffffffffff86165afa801561060d575f90612c8b575b6127109150608085013502049390612a51565b506020813d602011612cb7575b81612ca560209383613b0f565b8101031261015e576127109051612c78565b3d9150612c98565b9293927feb53ad58000000000000000000000000000000000000000000000000000000008103612edd575090612cf791810190613c49565b909492916040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260208160248173ffffffffffffffffffffffffffffffffffffffff87165afa90811561060d575f91612ea9575b5061271091612d6291614641565b04906040517f01664f6600000000000000000000000000000000000000000000000000000000815260208160048173ffffffffffffffffffffffffffffffffffffffff8b165afa801561060d57612dd89284925f92612e72575b5073ffffffffffffffffffffffffffffffffffffffff1661520c565b73ffffffffffffffffffffffffffffffffffffffff85163b1561015e576040517f9599127600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff92831660048201526024810191909152935f91859160449183918591165af192831561060d57600193612e6357506125a5565b612e6c90613a7a565b85612984565b73ffffffffffffffffffffffffffffffffffffffff919250612ea29060203d602011610a1d57610a0f8183613b0f565b9190612dbc565b90506020813d602011612ed5575b81612ec460209383613b0f565b8101031261015e5751612710612d54565b3d9150612eb7565b7f69b2a24e0000000000000000000000000000000000000000000000000000000081036131d9575090612f1291810190613c49565b91604095939195517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260208160248173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f165afa90811561060d575f916131a5575b5061271091612f9e91614641565b0494604051927ffae036d500000000000000000000000000000000000000000000000000000000845260208460048173ffffffffffffffffffffffffffffffffffffffff86165afa93841561060d575f94613170575b5092602073ffffffffffffffffffffffffffffffffffffffff946004604051809781937f313ce567000000000000000000000000000000000000000000000000000000008352165afa93841561060d575f94613132575b5061308d8773ffffffffffffffffffffffffffffffffffffffff84167f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f61520c565b73ffffffffffffffffffffffffffffffffffffffff82163b1561015e576040517f8d7ef9bb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9384166004820152670de0b6b3a76400009190910160ff94909416600a0a969096029290920460248601525f91859160449183918591165af192831561060d57600193612e6357506125a5565b9093506020813d602011613168575b8161314e60209383613b0f565b8101031261015e575160ff8116810361015e57928961304b565b3d9150613141565b93506020843d60201161319d575b8161318b60209383613b0f565b8101031261015e579251926020612ff4565b3d915061317e565b90506020813d6020116131d1575b816131c060209383613b0f565b8101031261015e5751612710612f90565b3d91506131b3565b9193917f1cc408a900000000000000000000000000000000000000000000000000000000810361324d5750830160a08482031261015e576132198461376a565b936132266020820161376a565b9060808101359567ffffffffffffffff871161015e576111486127f7946001988401613bc0565b7fc876d21d0000000000000000000000000000000000000000000000000000000081036112c65750836060918101031261015e5761328a8361376a565b926132976020820161376a565b73ffffffffffffffffffffffffffffffffffffffff8116949073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee86036133155750600194504791604081013583116132e6575b5050506125a5565b61330d92604073ffffffffffffffffffffffffffffffffffffffff920135900391166143b9565b8580806132de565b6020602496604051978880927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa92831561060d575f936133a4575b6001965060408101358411613373575b505050506125a5565b61339b93604073ffffffffffffffffffffffffffffffffffffffff920135900392169061433e565b8580808061336a565b92506020863d6020116133d1575b816133bf60209383613b0f565b8101031261015e57600195519261335a565b3d91506133b2565b7fffffffff000000000000000000000000000000000000000000000000000000006134048486613991565b929091167fe2ed3db40000000000000000000000000000000000000000000000000000000081036134d857506040519361016082848101031261015e5761344a8261376a565b9261345a81840160208501613bde565b9361346760a0850161376a565b9360c08101359667ffffffffffffffff881161015e576134a28260e06134986134cd9b886134aa9701908401613bc0565b9682019101613bde565b943691613b8a565b9473ffffffffffffffffffffffffffffffffffffffff80608435961692166141da565b6040525b8280612443565b909391907fedef505000000000000000000000000000000000000000000000000000000000810361358257506040519360a081838101031261015e5761357a9361355473ffffffffffffffffffffffffffffffffffffffff61354c84602061354261355e9761376a565b9782019101613bde565b941684614051565b5050933691613b8a565b906d1ff3684f28c67538d4d072c2273433149260843591614703565b6040526134d1565b7fbac152c500000000000000000000000000000000000000000000000000000000810361367c57506040519361010081838101031261015e576135c48161376a565b606082013567ffffffffffffffff811161015e57613673956135fd6135f161360593878701908701613bc0565b95850160808601613bde565b953691613b8a565b60406136146114a28351613f1d565b95602081518051605f8a01520151607f8801526020810151609f880152015160bf8601525f60df86015260208151910160ff86015e6084359273ffffffffffffffffffffffffffffffffffffffff602060408501359401359216614c02565b506040526134d1565b6109f1856040519384937f3c74eed60000000000000000000000000000000000000000000000000000000085525f600486015260248501526060604485015260648401916137ea565b602490604051907f9936cbab0000000000000000000000000000000000000000000000000000000082526004820152fd5b6020813588018035918291018437822082526020918201910161235b565b3461015e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261015e5760043573ffffffffffffffffffffffffffffffffffffffff81160361015e575f805360015ffd5b359073ffffffffffffffffffffffffffffffffffffffff8216820361015e57565b9181601f8401121561015e5782359167ffffffffffffffff831161015e576020808501948460051b01011161015e57565b9181601f8401121561015e5782359167ffffffffffffffff831161015e576020838186019501011161015e57565b601f82602094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe093818652868601375f8582860101520116010190565b33906d1ff3684f28c67538d4d072c22734331461384157565b367fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec013560601c9150565b73ffffffffffffffffffffffffffffffffffffffff90817ffc7be34027b4062d13b31d75182f37b703b5ad960f0e73236593535549bb277d5c1682821614610162577e9355806b743562f351db2e3726091207f49fa1cdccd5c65a7d4860ce3abbe99180835c1680151580613917575b6138e6575016905d565b602490604051907f77f944250000000000000000000000000000000000000000000000000000000082526004820152fd5b50803314156138dc565b73ffffffffffffffffffffffffffffffffffffffff7e9355806b743562f351db2e3726091207f49fa1cdccd5c65a7d4860ce3abbe95c16806139605750565b602490604051907f08a303650000000000000000000000000000000000000000000000000000000082526004820152fd5b80358101929160051b018210613a09573682101561015e5781359160208101602084830101818110613a0957361061015e57600484106139f7577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc602491359401910191565b634e487b715f5260326020526024601cfd5b611b2b565b8091939260051b013581019260051b018210613a09573682101561015e5781359160208101602084830101818110613a0957361061015e57600484106139f7577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc602491359401910191565b67ffffffffffffffff8111613a8e57604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6080810190811067ffffffffffffffff821117613a8e57604052565b6040810190811067ffffffffffffffff821117613a8e57604052565b6060810190811067ffffffffffffffff821117613a8e57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117613a8e57604052565b67ffffffffffffffff8111613a8e57601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b929192613b9682613b50565b91613ba46040519384613b0f565b82948184528183011161015e578281602093845f960137010152565b9080601f8301121561015e57816020613bdb93359101613b8a565b90565b80929103916080831261015e57604051906060820182811067ffffffffffffffff821117613a8e5780604052604083951261015e5760409181613c22606093613ad7565b613c2b8261376a565b81526020820135608086015284528281013560208501520135910152565b919082608091031261015e57613c5e8261376a565b9160208101359173ffffffffffffffffffffffffffffffffffffffff6040830135818116810361015e579260600135908116810361015e5790565b73ffffffffffffffffffffffffffffffffffffffff602435818116929183820361015e576044359081169081810361015e57606435948515801590613e64575b613ce6575b505050509050565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8103613d795750504791848310613d225750613d189293506143b9565b805f808080613cde565b6040517f97a6f3b900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9190911660048201526024810185905260448101839052606490fd5b909150604051927f70a08231000000000000000000000000000000000000000000000000000000008452306004850152602084602481855afa93841561060d575f94613e30575b50858410613dd95750613dd493945061433e565b613d18565b6040517f97a6f3b900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9190911660048201526024810186905260448101849052606490fd5b9093506020813d602011613e5c575b81613e4c60209383613b0f565b8101031261015e5751925f613dc0565b3d9150613e3f565b50801515613cd9565b73ffffffffffffffffffffffffffffffffffffffff92605592909184811685841680821015613f14575050915b6040519285165f52841660205262ffffff1660405260605f2090806040527f0000000000000000000000001f98431c8ad98523631ae4a59f267346ea31f9848152600b81019160ff8353602082015260407fe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54910152201690565b93509050613e9a565b60df01908160df11613f2b57565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b91929073ffffffffffffffffffffffffffffffffffffffff81163003613f88575050613f869250339061433e565b565b9150915082820160a08382031261015e57613fa39083613bde565b90608083013592831515840361015e578460a01161015e57613ffc613f8695613fcc3386614051565b50509260a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff603693019101613b8a565b92614703565b9061400c82613b50565b6140196040519182613b0f565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06140478294613b50565b0190602036910137565b604051929161405f84613ad7565b60208401915f83528473ffffffffffffffffffffffffffffffffffffffff809316905260208151015180935251511691565b6040519061409e82613af3565b602e82527f696e7432353620616d6f756e74290000000000000000000000000000000000006040837f546f6b656e5065726d697373696f6e73286164647265737320746f6b656e2c7560208201520152565b6040516140fc81613abb565b60588152613bdb603c60208301927f436f6e73696465726174696f6e286164647265737320746f6b656e2c75696e7484527f32353620616d6f756e742c6164647265737320636f756e74657270617274792c60408201527f626f6f6c207061727469616c46696c6c416c6c6f77656429000000000000000060608201526020614183614091565b6040519586937f436f6e73696465726174696f6e20636f6e73696465726174696f6e2900000000848601525180918686015e8301908482015f8152815193849201905e015f8382015203601c810184520182613b0f565b6141e8909693959682614051565b969190956141f68582614051565b6040989198519061420682613abb565b73ffffffffffffffffffffffffffffffffffffffff998a16825260208201528b891660408201525f60608201527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00180517f7d806873084f389a66fd0315dead7adaad8ae6e8b6cf9fb0d3db61e5a91c3ffa825260a0822091529a336d1ff3684f28c67538d4d072c22734149261429c94614703565b87846142a66140f0565b926142b095615084565b81604051936142be85613abb565b168352602083018490521660408201525f60608201527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00180517f7d806873084f389a66fd0315dead7adaad8ae6e8b6cf9fb0d3db61e5a91c3ffa825260a082209152906fffffffffffffffffffffffffffffffff1690613f8692615146565b60446020925f809373ffffffffffffffffffffffffffffffffffffffff966040519788947fa9059cbb00000000000000000000000000000000000000000000000000000000865216600485015260248401525af115610a8d57503d15601f3d1160015f51141617156143ac57565b6390b8ec185f526004601cfd5b5f80809381935af11561060d57565b3d156143f2573d906143d982613b50565b916143e76040519384613b0f565b82523d5f602084013e565b606090565b90929173ffffffffffffffffffffffffffffffffffffffff808316946e22d473030f116ddee9f6b43ac78ba38614801561462a575b610162575f91811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81036145335750505061445c9047615189565b938051155f146144b757505061448d575f80809381935af161447c6143c8565b90156144855750565b602081519101fd5b60046040517f01da1572000000000000000000000000000000000000000000000000000000008152fd5b90939260208301808411613f2b578251106139f757835f9460208695850101525b602083519301915af16144e96143c8565b90156144855751159081614529575b506144ff57565b60046040517f82d5d76a000000000000000000000000000000000000000000000000000000008152fd5b90503b155f6144f8565b9091949281979497155f146145525750505061448d575f9283926144d8565b604096959496939293517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526020918282602481875afa801561060d575f906145fb575b6145a79250615189565b92818101808211613f2b578851106145ea57865f9896949293838a9997958c948a010152036145d9575b5050506144d8565b6145e29261520c565b5f80876145d1565b603282634e487b715f52526024601cfd5b508282813d8311614623575b6146118183613b0f565b8101031261015e576145a7915161459d565b503d614607565b506d1ff3684f28c67538d4d072c22734861461442c565b81810292918115918404141715613f2b57565b9081602091031261015e575173ffffffffffffffffffffffffffffffffffffffff8116810361015e5790565b60406060916146b08482516020809173ffffffffffffffffffffffffffffffffffffffff81511684520151910152565b6020810151828501520151910152565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602080948051918291828752018686015e5f8582860101520116010190565b90919273ffffffffffffffffffffffffffffffffffffffff948580614726613828565b1695169485141580614b6b575b610162575f7f1643bf8e9fdaef48c4abf5a998de359be44a235ac7aebfbc05485e093720deaa90815c9182614b3a575b50816148fc57505015614842575161481857836020915151169382511691015191604051937f15dacbea00000000000000000000000000000000000000000000000000000000855260048501526024840152604483015260648201526020816084815f6d1ff3684f28c67538d4d072c227345af1801561060d576147e45750565b6020813d602011614810575b816147fd60209383613b0f565b8101031261015e57518015150361015e57565b3d91506147f0565b60046040517fc321526c000000000000000000000000000000000000000000000000000000008152fd5b9350916e22d473030f116ddee9f6b43ac78ba390813b1561015e575f80946148e26148ca976148a294604051998a98899788967f30f28b7a0000000000000000000000000000000000000000000000000000000088526004880190614680565b805173ffffffffffffffffffffffffffffffffffffffff1660848701526020015160a4860152565b60c484015261010060e48401526101048301906146c0565b03925af1801561060d576148f35750565b613f8690613a7a565b909691959294939291168103610162577f7070616765290000000000000000000000000000000000000000000000000000604095614a1a6046886020815161494381613abb565b605b81528181017f416374696f6e73416e64536c697070616765286164647265737320627579546f81527f6b656e2c6164647265737320726563697069656e742c75696e74323536206d69848301527f6e416d6f756e744f75742c62797465735b5d20616374696f6e7329000000000060608301526149c0614091565b9184519889957f416374696f6e73416e64536c69707061676520616374696f6e73416e64536c69868801528601525180918686015e8301908482015f8152815193849201905e015f83820152036026810185520183613b0f565b614b11576e22d473030f116ddee9f6b43ac78ba392833b1561015e57614af55f96614ac48894614aa69b614a7e978c519d8e9b8c9a8b997f137c29fe000000000000000000000000000000000000000000000000000000008b5260048b0190614680565b805173ffffffffffffffffffffffffffffffffffffffff1660848a01526020015160a4890152565b60c487015260e48601526101406101048601526101448501906146c0565b907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc848303016101248501526146c0565b03925af1908115614b0857506148f35750565b513d5f823e3d90fd5b600486517f1c500e5c000000000000000000000000000000000000000000000000000000008152fd5b90505f7ffc7be34027b4062d13b31d75182f37b703b5ad960f0e73236593535549bb277d9181835c935d5d5f614763565b50857e9355806b743562f351db2e3726091207f49fa1cdccd5c65a7d4860ce3abbe9805c9081614ba0575b5016331415614733565b5f905d5f614b96565b919360a093613bdb969573ffffffffffffffffffffffffffffffffffffffff809416855215156020850152604084015216606082015281608082015201906146c0565b919082604091031261015e576020825192015190565b92939095917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8111611b2b575b865190602b82106139f757601488015160178901519088602b8b015192829684859873ffffffffffffffffffffffffffffffffffffffff871673ffffffffffffffffffffffffffffffffffffffff8716101561507b575b614c91828583613e6d565b9385519284603f880152602b87015260178601526014850152835273ffffffffffffffffffffffffffffffffffffffff309116145f14614ef4579073ffffffffffffffffffffffffffffffffffffffff83928a86602b8a115f14614ee657838092505f91614d4e30975b838316848b16108514614ecc576401000276a45b60409d8e9a8b519c8d9b8c9a8b987f128acb08000000000000000000000000000000000000000000000000000000008a52169116109060048701614ba9565b0393165af1908115614ec2575f945f92614e78575b505073ffffffffffffffffffffffffffffffffffffffff809194935b1691161015614e7157505b7f80000000000000000000000000000000000000000000000000000000000000008114613f2b575f03915f8312611b2b57602b83921115614e0957505030909560178151106139f757807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe96017925101828201520195603f8652614c2f565b9493509550509250808410614e1c575050565b6040517f97a6f3b900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff929092166004830152602482015260448101839052606490fd5b9050614d8a565b73ffffffffffffffffffffffffffffffffffffffff95508592509081614eb292903d10614ebb575b614eaa8183613b0f565b810190614bec565b94909491614d63565b503d614ea0565b84513d5f823e3d90fd5b73fffd8963efd1fc6a506488495d951d5263988d25614d0f565b835f91614d4e829497614cfb565b9293919273ffffffffffffffffffffffffffffffffffffffff16919050602b8511156150745730915b73ffffffffffffffffffffffffffffffffffffffff851673ffffffffffffffffffffffffffffffffffffffff8516105f14615059576401000276a4925b60405180918d602096878401967f128acb0800000000000000000000000000000000000000000000000000000000885273ffffffffffffffffffffffffffffffffffffffff8b1673ffffffffffffffffffffffffffffffffffffffff8b16106024860194614fc795614ba9565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018252614ff79082613b0f565b6150008261386c565b515a925f8094938194f1906150136143c8565b91156150535761504b73ffffffffffffffffffffffffffffffffffffffff949392859261503e613921565b8082518301019101614bec565b949093614d7f565b81519101fd5b73fffd8963efd1fc6a506488495d951d5263988d2592614f5a565b8791614f1d565b50508385614c86565b91909294936e22d473030f116ddee9f6b43ac78ba392833b1561015e576148e25f96614ac488946151279a73ffffffffffffffffffffffffffffffffffffffff6150ff986040519d8e9c8d9b8c9a7f137c29fe000000000000000000000000000000000000000000000000000000008c5260048c0190614680565b805173ffffffffffffffffffffffffffffffffffffffff1660848b01526020015160a48a0152565b1660c487015260e48601526101406101048601526101448501906146c0565b9190917f4efcac36537dd5721596376472101aec5ff380b23b286c66cdfe70a509c0cef35f526020526040519160405260605f20916040526010525f5260305fa0565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff828209828202918280831092039180830391612710958691099282861115611b2b5714615206577fbc01a36e2eb1c432ca57a786c226809d495182a9930be0ded288ce703afb7e919350828211900360fc1b910360041c170290565b50500490565b9173ffffffffffffffffffffffffffffffffffffffff9182916040519384927fdd62ed3e0000000000000000000000000000000000000000000000000000000084523060048501521692836024840152826044602096879389165afa91821561060d575f92615371575b508110615284575b50505050565b615312575b60445f91826040519586927f095ea7b300000000000000000000000000000000000000000000000000000000845260048401527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60248401525af115610a8d57503d15601f3d1160015f5114161715615305575f80808061527e565b633e3f8f735f526004601cfd5b6040517f095ea7b30000000000000000000000000000000000000000000000000000000081528160048201525f6024820152825f60448382885af115610a8d57503d15601f3d1160015f5114161761528957633e3f8f735f526004601cfd5b9091508381813d8311615399575b6153898183613b0f565b8101031261015e5751905f615276565b503d61537f565b917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82840981838502938480841093039509908085146154275782805f0316809304600280826003021880830282030280830282030280830282030280830282030280830282030280920290030294600184805f0304019185841191030302920304170290565b50509150049056

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

0000000000000000000000001f98431c8ad98523631ae4a59f267346ea31f984e34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b540000000000000000000000006b175474e89094c44da98b954eedeac495271d0f

-----Decoded View---------------
Arg [0] : uniFactory (address): 0x1F98431c8aD98523631AE4a59f267346ea31F984
Arg [1] : poolInitCodeHash (bytes32): 0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54
Arg [2] : dai (address): 0x6B175474E89094C44Da98b954EedeAC495271d0F

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 0000000000000000000000001f98431c8ad98523631ae4a59f267346ea31f984
Arg [1] : e34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54
Arg [2] : 0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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