ETH Price: $2,655.54 (+0.48%)

Contract

0xfb2809A5314473E1165f6B58018E20ed8F07B840
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

Latest 21 internal transactions

Advanced mode:
Parent Transaction Hash Block From To
204148292024-07-29 21:11:4724 days ago1722287507
0xfb2809A5...d8F07B840
0.00053076 ETH
204148292024-07-29 21:11:4724 days ago1722287507
0xfb2809A5...d8F07B840
0.00000808 ETH
204148292024-07-29 21:11:4724 days ago1722287507
0xfb2809A5...d8F07B840
0.00053885 ETH
203443572024-07-20 1:07:2334 days ago1721437643
0xfb2809A5...d8F07B840
0.00109498 ETH
203443572024-07-20 1:07:2334 days ago1721437643
0xfb2809A5...d8F07B840
0.00001667 ETH
203443572024-07-20 1:07:2334 days ago1721437643
0xfb2809A5...d8F07B840
0.00111165 ETH
203247892024-07-17 7:35:2337 days ago1721201723
0xfb2809A5...d8F07B840
0.00203089 ETH
203247892024-07-17 7:35:2337 days ago1721201723
0xfb2809A5...d8F07B840
0.00003092 ETH
203247892024-07-17 7:35:2337 days ago1721201723
0xfb2809A5...d8F07B840
0.00206182 ETH
202874652024-07-12 2:32:5942 days ago1720751579
0xfb2809A5...d8F07B840
0.00085934 ETH
202874652024-07-12 2:32:5942 days ago1720751579
0xfb2809A5...d8F07B840
0.00001308 ETH
202874652024-07-12 2:32:5942 days ago1720751579
0xfb2809A5...d8F07B840
0.00087242 ETH
202836982024-07-11 13:55:1142 days ago1720706111
0xfb2809A5...d8F07B840
0.00222211 ETH
202836982024-07-11 13:55:1142 days ago1720706111
0xfb2809A5...d8F07B840
0.00003383 ETH
202836982024-07-11 13:55:1142 days ago1720706111
0xfb2809A5...d8F07B840
0.00225595 ETH
202356042024-07-04 20:42:5949 days ago1720125779
0xfb2809A5...d8F07B840
0.00282424 ETH
202356042024-07-04 20:42:5949 days ago1720125779
0xfb2809A5...d8F07B840
0.000043 ETH
202356042024-07-04 20:42:5949 days ago1720125779
0xfb2809A5...d8F07B840
0.00286724 ETH
195827472024-04-04 13:38:11140 days ago1712237891
0xfb2809A5...d8F07B840
0 ETH
195827472024-04-04 13:38:11140 days ago1712237891
0xfb2809A5...d8F07B840
 Contract Creation0 ETH
195827472024-04-04 13:38:11140 days ago1712237891  Contract Creation0 ETH
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Settlement

Compiler Version
v0.8.23+commit.f704f362

Optimization Enabled:
Yes with 1000000 runs

Other Settings:
shanghai EvmVersion
File 1 of 32 : Settlement.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.23;

import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IOrderMixin } from "@1inch/limit-order-protocol-contract/contracts/interfaces/IOrderMixin.sol";

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

/**
 * @title Settlement contract
 * @notice Contract to execute limit orders settlement on Mainnet, created by Fusion mode.
 */
contract Settlement is SimpleSettlement {
    error InvalidPriorityFee();

    constructor(address limitOrderProtocol, IERC20 feeToken, address weth, address owner)
        SimpleSettlement(limitOrderProtocol, feeToken, weth, owner)
    {}

    function _postInteraction(
        IOrderMixin.Order calldata order,
        bytes calldata extension,
        bytes32 orderHash,
        address taker,
        uint256 makingAmount,
        uint256 takingAmount,
        uint256 remainingMakingAmount,
        bytes calldata extraData
    ) internal virtual override {
        if (!_isPriorityFeeValid()) revert InvalidPriorityFee();
        super._postInteraction(order, extension, orderHash, taker, makingAmount, takingAmount, remainingMakingAmount, extraData);
    }

    /**
     * @dev Validates priority fee according to the spec
     * https://snapshot.org/#/1inch.eth/proposal/0xa040c60050147a0f67042ae024673e92e813b5d2c0f748abf70ddfa1ed107cbe
     * For blocks with baseFee <10.6 gwei – the priorityFee is capped at 70% of the baseFee.
     * For blocks with baseFee between 10.6 gwei and 104.1 gwei – the priorityFee is capped at 50% of the baseFee.
     * For blocks with baseFee >104.1 gwei – priorityFee is capped at 65% of the block’s baseFee.
     */
    function _isPriorityFeeValid() internal view returns(bool) {
        unchecked {
            uint256 baseFee = block.basefee;
            uint256 priorityFee = tx.gasprice - baseFee;

            if (baseFee < 10.6 gwei) {
                return priorityFee * 100 <= baseFee * 70;
            } else if (baseFee > 104.1 gwei) {
                return priorityFee * 100 <= baseFee * 65;
            } else {
                return priorityFee * 2 <= baseFee;
            }
        }
    }
}

File 2 of 32 : IAmountGetter.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./IOrderMixin.sol";

interface IAmountGetter {
    /**
     * @notice View method that gets called to determine the actual making amount
     * @param order Order being processed
     * @param extension Order extension data
     * @param orderHash Hash of the order being processed
     * @param taker Taker address
     * @param takingAmount Actual taking amount
     * @param remainingMakingAmount Order remaining making amount
     * @param extraData Extra data
     */
    function getMakingAmount(
        IOrderMixin.Order calldata order,
        bytes calldata extension,
        bytes32 orderHash,
        address taker,
        uint256 takingAmount,
        uint256 remainingMakingAmount,
        bytes calldata extraData
    ) external view returns (uint256);

    /**
     * @notice View method that gets called to determine the actual making amount
     * @param order Order being processed
     * @param extension Order extension data
     * @param orderHash Hash of the order being processed
     * @param taker Taker address
     * @param makingAmount Actual taking amount
     * @param remainingMakingAmount Order remaining making amount
     * @param extraData Extra data
     */
    function getTakingAmount(
        IOrderMixin.Order calldata order,
        bytes calldata extension,
        bytes32 orderHash,
        address taker,
        uint256 makingAmount,
        uint256 remainingMakingAmount,
        bytes calldata extraData
    ) external view returns (uint256);
}

File 3 of 32 : IOrderMixin.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "@1inch/solidity-utils/contracts/libraries/AddressLib.sol";
import "../libraries/MakerTraitsLib.sol";
import "../libraries/TakerTraitsLib.sol";

interface IOrderMixin {
    struct Order {
        uint256 salt;
        Address maker;
        Address receiver;
        Address makerAsset;
        Address takerAsset;
        uint256 makingAmount;
        uint256 takingAmount;
        MakerTraits makerTraits;
    }

    error InvalidatedOrder();
    error TakingAmountExceeded();
    error PrivateOrder();
    error BadSignature();
    error OrderExpired();
    error WrongSeriesNonce();
    error SwapWithZeroAmount();
    error PartialFillNotAllowed();
    error OrderIsNotSuitableForMassInvalidation();
    error EpochManagerAndBitInvalidatorsAreIncompatible();
    error ReentrancyDetected();
    error PredicateIsNotTrue();
    error TakingAmountTooHigh();
    error MakingAmountTooLow();
    error TransferFromMakerToTakerFailed();
    error TransferFromTakerToMakerFailed();
    error MismatchArraysLengths();
    error InvalidPermit2Transfer();
    error SimulationResults(bool success, bytes res);

    /**
     * @notice Emitted when order gets filled
     * @param orderHash Hash of the order
     * @param remainingAmount Amount of the maker asset that remains to be filled
     */
    event OrderFilled(
        bytes32 orderHash,
        uint256 remainingAmount
    );

    /**
     * @notice Emitted when order without `useBitInvalidator` gets cancelled
     * @param orderHash Hash of the order
     */
    event OrderCancelled(
        bytes32 orderHash
    );

    /**
     * @notice Emitted when order with `useBitInvalidator` gets cancelled
     * @param maker Maker address
     * @param slotIndex Slot index that was updated
     * @param slotValue New slot value
     */
    event BitInvalidatorUpdated(
        address indexed maker,
        uint256 slotIndex,
        uint256 slotValue
    );

    /**
     * @notice Returns bitmask for double-spend invalidators based on lowest byte of order.info and filled quotes
     * @param maker Maker address
     * @param slot Slot number to return bitmask for
     * @return result Each bit represents whether corresponding was already invalidated
     */
    function bitInvalidatorForOrder(address maker, uint256 slot) external view returns(uint256 result);

    /**
     * @notice Returns bitmask for double-spend invalidators based on lowest byte of order.info and filled quotes
     * @param orderHash Hash of the order
     * @return remaining Remaining amount of the order
     */
    function remainingInvalidatorForOrder(address maker, bytes32 orderHash) external view returns(uint256 remaining);

    /**
     * @notice Returns bitmask for double-spend invalidators based on lowest byte of order.info and filled quotes
     * @param orderHash Hash of the order
     * @return remainingRaw Inverse of the remaining amount of the order if order was filled at least once, otherwise 0
     */
    function rawRemainingInvalidatorForOrder(address maker, bytes32 orderHash) external view returns(uint256 remainingRaw);

    /**
     * @notice Cancels order's quote
     * @param makerTraits Order makerTraits
     * @param orderHash Hash of the order to cancel
     */
    function cancelOrder(MakerTraits makerTraits, bytes32 orderHash) external;

    /**
     * @notice Cancels orders' quotes
     * @param makerTraits Orders makerTraits
     * @param orderHashes Hashes of the orders to cancel
     */
    function cancelOrders(MakerTraits[] calldata makerTraits, bytes32[] calldata orderHashes) external;

    /**
     * @notice Cancels all quotes of the maker (works for bit-invalidating orders only)
     * @param makerTraits Order makerTraits
     * @param additionalMask Additional bitmask to invalidate orders
     */
    function bitsInvalidateForOrder(MakerTraits makerTraits, uint256 additionalMask) external;

    /**
     * @notice Returns order hash, hashed with limit order protocol contract EIP712
     * @param order Order
     * @return orderHash Hash of the order
     */
    function hashOrder(IOrderMixin.Order calldata order) external view returns(bytes32 orderHash);

    /**
     * @notice Delegates execution to custom implementation. Could be used to validate if `transferFrom` works properly
     * @dev The function always reverts and returns the simulation results in revert data.
     * @param target Addresses that will be delegated
     * @param data Data that will be passed to delegatee
     */
    function simulate(address target, bytes calldata data) external;

    /**
     * @notice Fills order's quote, fully or partially (whichever is possible).
     * @param order Order quote to fill
     * @param r R component of signature
     * @param vs VS component of signature
     * @param amount Taker amount to fill
     * @param takerTraits Specifies threshold as maximum allowed takingAmount when takingAmount is zero, otherwise specifies
     * minimum allowed makingAmount. The 2nd (0 based index) highest bit specifies whether taker wants to skip maker's permit.
     * @return makingAmount Actual amount transferred from maker to taker
     * @return takingAmount Actual amount transferred from taker to maker
     * @return orderHash Hash of the filled order
     */
    function fillOrder(
        Order calldata order,
        bytes32 r,
        bytes32 vs,
        uint256 amount,
        TakerTraits takerTraits
    ) external payable returns(uint256 makingAmount, uint256 takingAmount, bytes32 orderHash);

    /**
     * @notice Same as `fillOrder` but allows to specify arguments that are used by the taker.
     * @param order Order quote to fill
     * @param r R component of signature
     * @param vs VS component of signature
     * @param amount Taker amount to fill
     * @param takerTraits Specifies threshold as maximum allowed takingAmount when takingAmount is zero, otherwise specifies
     * minimum allowed makingAmount. The 2nd (0 based index) highest bit specifies whether taker wants to skip maker's permit.
     * @param args Arguments that are used by the taker (target, extension, interaction, permit)
     * @return makingAmount Actual amount transferred from maker to taker
     * @return takingAmount Actual amount transferred from taker to maker
     * @return orderHash Hash of the filled order
     */
    function fillOrderArgs(
        IOrderMixin.Order calldata order,
        bytes32 r,
        bytes32 vs,
        uint256 amount,
        TakerTraits takerTraits,
        bytes calldata args
    ) external payable returns(uint256 makingAmount, uint256 takingAmount, bytes32 orderHash);

    /**
     * @notice Same as `fillOrder` but uses contract-based signatures.
     * @param order Order quote to fill
     * @param signature Signature to confirm quote ownership
     * @param amount Taker amount to fill
     * @param takerTraits Specifies threshold as maximum allowed takingAmount when takingAmount is zero, otherwise specifies
     * minimum allowed makingAmount. The 2nd (0 based index) highest bit specifies whether taker wants to skip maker's permit.
     * @return makingAmount Actual amount transferred from maker to taker
     * @return takingAmount Actual amount transferred from taker to maker
     * @return orderHash Hash of the filled order
     * @dev See tests for examples
     */
    function fillContractOrder(
        Order calldata order,
        bytes calldata signature,
        uint256 amount,
        TakerTraits takerTraits
    ) external returns(uint256 makingAmount, uint256 takingAmount, bytes32 orderHash);

    /**
     * @notice Same as `fillContractOrder` but allows to specify arguments that are used by the taker.
     * @param order Order quote to fill
     * @param signature Signature to confirm quote ownership
     * @param amount Taker amount to fill
     * @param takerTraits Specifies threshold as maximum allowed takingAmount when takingAmount is zero, otherwise specifies
     * minimum allowed makingAmount. The 2nd (0 based index) highest bit specifies whether taker wants to skip maker's permit.
     * @param args Arguments that are used by the taker (target, extension, interaction, permit)
     * @return makingAmount Actual amount transferred from maker to taker
     * @return takingAmount Actual amount transferred from taker to maker
     * @return orderHash Hash of the filled order
     * @dev See tests for examples
     */
    function fillContractOrderArgs(
        Order calldata order,
        bytes calldata signature,
        uint256 amount,
        TakerTraits takerTraits,
        bytes calldata args
    ) external returns(uint256 makingAmount, uint256 takingAmount, bytes32 orderHash);
}

File 4 of 32 : IPostInteraction.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./IOrderMixin.sol";

interface IPostInteraction {
    /**
     * @notice Callback method that gets called after all fund transfers
     * @param order Order being processed
     * @param extension Order extension data
     * @param orderHash Hash of the order being processed
     * @param taker Taker address
     * @param makingAmount Actual making amount
     * @param takingAmount Actual taking amount
     * @param remainingMakingAmount Order remaining making amount
     * @param extraData Extra data
     */
    function postInteraction(
        IOrderMixin.Order calldata order,
        bytes calldata extension,
        bytes32 orderHash,
        address taker,
        uint256 makingAmount,
        uint256 takingAmount,
        uint256 remainingMakingAmount,
        bytes calldata extraData
    ) external;
}

File 5 of 32 : IPreInteraction.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./IOrderMixin.sol";

interface IPreInteraction {
    /**
     * @notice Callback method that gets called before any funds transfers
     * @param order Order being processed
     * @param extension Order extension data
     * @param orderHash Hash of the order being processed
     * @param taker Taker address
     * @param makingAmount Actual making amount
     * @param takingAmount Actual taking amount
     * @param remainingMakingAmount Order remaining making amount
     * @param extraData Extra data
     */
    function preInteraction(
        IOrderMixin.Order calldata order,
        bytes calldata extension,
        bytes32 orderHash,
        address taker,
        uint256 makingAmount,
        uint256 takingAmount,
        uint256 remainingMakingAmount,
        bytes calldata extraData
    ) external;
}

File 6 of 32 : MakerTraitsLib.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

type MakerTraits is uint256;

/**
 * @title MakerTraitsLib
 * @notice A library to manage and check MakerTraits, which are used to encode the maker's preferences for an order in a single uint256.
 * @dev
 * The MakerTraits type is a uint256 and different parts of the number are used to encode different traits.
 * High bits are used for flags
 * 255 bit `NO_PARTIAL_FILLS_FLAG`          - if set, the order does not allow partial fills
 * 254 bit `ALLOW_MULTIPLE_FILLS_FLAG`      - if set, the order permits multiple fills
 * 253 bit                                  - unused
 * 252 bit `PRE_INTERACTION_CALL_FLAG`      - if set, the order requires pre-interaction call
 * 251 bit `POST_INTERACTION_CALL_FLAG`     - if set, the order requires post-interaction call
 * 250 bit `NEED_CHECK_EPOCH_MANAGER_FLAG`  - if set, the order requires to check the epoch manager
 * 249 bit `HAS_EXTENSION_FLAG`             - if set, the order has extension(s)
 * 248 bit `USE_PERMIT2_FLAG`               - if set, the order uses permit2
 * 247 bit `UNWRAP_WETH_FLAG`               - if set, the order requires to unwrap WETH

 * Low 200 bits are used for allowed sender, expiration, nonceOrEpoch, and series
 * uint80 last 10 bytes of allowed sender address (0 if any)
 * uint40 expiration timestamp (0 if none)
 * uint40 nonce or epoch
 * uint40 series
 */
library MakerTraitsLib {
    // Low 200 bits are used for allowed sender, expiration, nonceOrEpoch, and series
    uint256 private constant _ALLOWED_SENDER_MASK = type(uint80).max;
    uint256 private constant _EXPIRATION_OFFSET = 80;
    uint256 private constant _EXPIRATION_MASK = type(uint40).max;
    uint256 private constant _NONCE_OR_EPOCH_OFFSET = 120;
    uint256 private constant _NONCE_OR_EPOCH_MASK = type(uint40).max;
    uint256 private constant _SERIES_OFFSET = 160;
    uint256 private constant _SERIES_MASK = type(uint40).max;

    uint256 private constant _NO_PARTIAL_FILLS_FLAG = 1 << 255;
    uint256 private constant _ALLOW_MULTIPLE_FILLS_FLAG = 1 << 254;
    uint256 private constant _PRE_INTERACTION_CALL_FLAG = 1 << 252;
    uint256 private constant _POST_INTERACTION_CALL_FLAG = 1 << 251;
    uint256 private constant _NEED_CHECK_EPOCH_MANAGER_FLAG = 1 << 250;
    uint256 private constant _HAS_EXTENSION_FLAG = 1 << 249;
    uint256 private constant _USE_PERMIT2_FLAG = 1 << 248;
    uint256 private constant _UNWRAP_WETH_FLAG = 1 << 247;

    /**
     * @notice Checks if the order has the extension flag set.
     * @dev If the `HAS_EXTENSION_FLAG` is set in the makerTraits, then the protocol expects that the order has extension(s).
     * @param makerTraits The traits of the maker.
     * @return result A boolean indicating whether the flag is set.
     */
    function hasExtension(MakerTraits makerTraits) internal pure returns (bool) {
        return (MakerTraits.unwrap(makerTraits) & _HAS_EXTENSION_FLAG) != 0;
    }

    /**
     * @notice Checks if the maker allows a specific taker to fill the order.
     * @param makerTraits The traits of the maker.
     * @param sender The address of the taker to be checked.
     * @return result A boolean indicating whether the taker is allowed.
     */
    function isAllowedSender(MakerTraits makerTraits, address sender) internal pure returns (bool) {
        uint160 allowedSender = uint160(MakerTraits.unwrap(makerTraits) & _ALLOWED_SENDER_MASK);
        return allowedSender == 0 || allowedSender == uint160(sender) & _ALLOWED_SENDER_MASK;
    }

    /**
     * @notice Checks if the order has expired.
     * @param makerTraits The traits of the maker.
     * @return result A boolean indicating whether the order has expired.
     */
    function isExpired(MakerTraits makerTraits) internal view returns (bool) {
        uint256 expiration = (MakerTraits.unwrap(makerTraits) >> _EXPIRATION_OFFSET) & _EXPIRATION_MASK;
        return expiration != 0 && expiration < block.timestamp;  // solhint-disable-line not-rely-on-time
    }

    /**
     * @notice Returns the nonce or epoch of the order.
     * @param makerTraits The traits of the maker.
     * @return result The nonce or epoch of the order.
     */
    function nonceOrEpoch(MakerTraits makerTraits) internal pure returns (uint256) {
        return (MakerTraits.unwrap(makerTraits) >> _NONCE_OR_EPOCH_OFFSET) & _NONCE_OR_EPOCH_MASK;
    }

    /**
     * @notice Returns the series of the order.
     * @param makerTraits The traits of the maker.
     * @return result The series of the order.
     */
    function series(MakerTraits makerTraits) internal pure returns (uint256) {
        return (MakerTraits.unwrap(makerTraits) >> _SERIES_OFFSET) & _SERIES_MASK;
    }

    /**
      * @notice Determines if the order allows partial fills.
      * @dev If the _NO_PARTIAL_FILLS_FLAG is not set in the makerTraits, then the order allows partial fills.
      * @param makerTraits The traits of the maker, determining their preferences for the order.
      * @return result A boolean indicating whether the maker allows partial fills.
      */
    function allowPartialFills(MakerTraits makerTraits) internal pure returns (bool) {
        return (MakerTraits.unwrap(makerTraits) & _NO_PARTIAL_FILLS_FLAG) == 0;
    }

    /**
     * @notice Checks if the maker needs pre-interaction call.
     * @param makerTraits The traits of the maker.
     * @return result A boolean indicating whether the maker needs a pre-interaction call.
     */
    function needPreInteractionCall(MakerTraits makerTraits) internal pure returns (bool) {
        return (MakerTraits.unwrap(makerTraits) & _PRE_INTERACTION_CALL_FLAG) != 0;
    }

    /**
     * @notice Checks if the maker needs post-interaction call.
     * @param makerTraits The traits of the maker.
     * @return result A boolean indicating whether the maker needs a post-interaction call.
     */
    function needPostInteractionCall(MakerTraits makerTraits) internal pure returns (bool) {
        return (MakerTraits.unwrap(makerTraits) & _POST_INTERACTION_CALL_FLAG) != 0;
    }

    /**
      * @notice Determines if the order allows multiple fills.
      * @dev If the _ALLOW_MULTIPLE_FILLS_FLAG is set in the makerTraits, then the maker allows multiple fills.
      * @param makerTraits The traits of the maker, determining their preferences for the order.
      * @return result A boolean indicating whether the maker allows multiple fills.
      */
    function allowMultipleFills(MakerTraits makerTraits) internal pure returns (bool) {
        return (MakerTraits.unwrap(makerTraits) & _ALLOW_MULTIPLE_FILLS_FLAG) != 0;
    }

    /**
      * @notice Determines if an order should use the bit invalidator or remaining amount validator.
      * @dev The bit invalidator can be used if the order does not allow partial or multiple fills.
      * @param makerTraits The traits of the maker, determining their preferences for the order.
      * @return result A boolean indicating whether the bit invalidator should be used.
      * True if the order requires the use of the bit invalidator.
      */
    function useBitInvalidator(MakerTraits makerTraits) internal pure returns (bool) {
        return !allowPartialFills(makerTraits) || !allowMultipleFills(makerTraits);
    }

    /**
     * @notice Checks if the maker needs to check the epoch.
     * @param makerTraits The traits of the maker.
     * @return result A boolean indicating whether the maker needs to check the epoch manager.
     */
    function needCheckEpochManager(MakerTraits makerTraits) internal pure returns (bool) {
        return (MakerTraits.unwrap(makerTraits) & _NEED_CHECK_EPOCH_MANAGER_FLAG) != 0;
    }

    /**
     * @notice Checks if the maker uses permit2.
     * @param makerTraits The traits of the maker.
     * @return result A boolean indicating whether the maker uses permit2.
     */
    function usePermit2(MakerTraits makerTraits) internal pure returns (bool) {
        return MakerTraits.unwrap(makerTraits) & _USE_PERMIT2_FLAG != 0;
    }

    /**
     * @notice Checks if the maker needs to unwraps WETH.
     * @param makerTraits The traits of the maker.
     * @return result A boolean indicating whether the maker needs to unwrap WETH.
     */
    function unwrapWeth(MakerTraits makerTraits) internal pure returns (bool) {
        return MakerTraits.unwrap(makerTraits) & _UNWRAP_WETH_FLAG != 0;
    }
}

File 7 of 32 : TakerTraitsLib.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

type TakerTraits is uint256;

/**
 * @title TakerTraitsLib
 * @notice This library to manage and check TakerTraits, which are used to encode the taker's preferences for an order in a single uint256.
 * @dev The TakerTraits are structured as follows:
 * High bits are used for flags
 * 255 bit `_MAKER_AMOUNT_FLAG`           - If set, the taking amount is calculated based on making amount, otherwise making amount is calculated based on taking amount.
 * 254 bit `_UNWRAP_WETH_FLAG`            - If set, the WETH will be unwrapped into ETH before sending to taker.
 * 253 bit `_SKIP_ORDER_PERMIT_FLAG`      - If set, the order skips maker's permit execution.
 * 252 bit `_USE_PERMIT2_FLAG`            - If set, the order uses the permit2 function for authorization.
 * 251 bit `_ARGS_HAS_TARGET`             - If set, then first 20 bytes of args are treated as target address for maker’s funds transfer.
 * 224-247 bits `ARGS_EXTENSION_LENGTH`   - The length of the extension calldata in the args.
 * 200-223 bits `ARGS_INTERACTION_LENGTH` - The length of the interaction calldata in the args.
 * 0-184 bits                             - The threshold amount (the maximum amount a taker agrees to give in exchange for a making amount).
 */
library TakerTraitsLib {
    uint256 private constant _MAKER_AMOUNT_FLAG = 1 << 255;
    uint256 private constant _UNWRAP_WETH_FLAG = 1 << 254;
    uint256 private constant _SKIP_ORDER_PERMIT_FLAG = 1 << 253;
    uint256 private constant _USE_PERMIT2_FLAG = 1 << 252;
    uint256 private constant _ARGS_HAS_TARGET = 1 << 251;

    uint256 private constant _ARGS_EXTENSION_LENGTH_OFFSET = 224;
    uint256 private constant _ARGS_EXTENSION_LENGTH_MASK = 0xffffff;
    uint256 private constant _ARGS_INTERACTION_LENGTH_OFFSET = 200;
    uint256 private constant _ARGS_INTERACTION_LENGTH_MASK = 0xffffff;

    uint256 private constant _AMOUNT_MASK = 0x000000000000000000ffffffffffffffffffffffffffffffffffffffffffffff;

    /**
     * @notice Checks if the args should contain target address.
     * @param takerTraits The traits of the taker.
     * @return result A boolean indicating whether the args should contain target address.
     */
    function argsHasTarget(TakerTraits takerTraits) internal pure returns (bool) {
        return (TakerTraits.unwrap(takerTraits) & _ARGS_HAS_TARGET) != 0;
    }

    /**
     * @notice Retrieves the length of the extension calldata from the takerTraits.
     * @param takerTraits The traits of the taker.
     * @return result The length of the extension calldata encoded in the takerTraits.
     */
    function argsExtensionLength(TakerTraits takerTraits) internal pure returns (uint256) {
        return (TakerTraits.unwrap(takerTraits) >> _ARGS_EXTENSION_LENGTH_OFFSET) & _ARGS_EXTENSION_LENGTH_MASK;
    }

    /**
     * @notice Retrieves the length of the interaction calldata from the takerTraits.
     * @param takerTraits The traits of the taker.
     * @return result The length of the interaction calldata encoded in the takerTraits.
     */
    function argsInteractionLength(TakerTraits takerTraits) internal pure returns (uint256) {
        return (TakerTraits.unwrap(takerTraits) >> _ARGS_INTERACTION_LENGTH_OFFSET) & _ARGS_INTERACTION_LENGTH_MASK;
    }

    /**
     * @notice Checks if the taking amount should be calculated based on making amount.
     * @param takerTraits The traits of the taker.
     * @return result A boolean indicating whether the taking amount should be calculated based on making amount.
     */
    function isMakingAmount(TakerTraits takerTraits) internal pure returns (bool) {
        return (TakerTraits.unwrap(takerTraits) & _MAKER_AMOUNT_FLAG) != 0;
    }

    /**
     * @notice Checks if the order should unwrap WETH and send ETH to taker.
     * @param takerTraits The traits of the taker.
     * @return result A boolean indicating whether the order should unwrap WETH.
     */
    function unwrapWeth(TakerTraits takerTraits) internal pure returns (bool) {
        return (TakerTraits.unwrap(takerTraits) & _UNWRAP_WETH_FLAG) != 0;
    }

    /**
     * @notice Checks if the order should skip maker's permit execution.
     * @param takerTraits The traits of the taker.
     * @return result A boolean indicating whether the order don't apply permit.
     */
    function skipMakerPermit(TakerTraits takerTraits) internal pure returns (bool) {
        return (TakerTraits.unwrap(takerTraits) & _SKIP_ORDER_PERMIT_FLAG) != 0;
    }

    /**
     * @notice Checks if the order uses the permit2 instead of permit.
     * @param takerTraits The traits of the taker.
     * @return result A boolean indicating whether the order uses the permit2.
     */
    function usePermit2(TakerTraits takerTraits) internal pure returns (bool) {
        return (TakerTraits.unwrap(takerTraits) & _USE_PERMIT2_FLAG) != 0;
    }

    /**
     * @notice Retrieves the threshold amount from the takerTraits.
     * The maximum amount a taker agrees to give in exchange for a making amount.
     * @param takerTraits The traits of the taker.
     * @return result The threshold amount encoded in the takerTraits.
     */
    function threshold(TakerTraits takerTraits) internal pure returns (uint256) {
        return TakerTraits.unwrap(takerTraits) & _AMOUNT_MASK;
    }
}

File 8 of 32 : IDaiLikePermit.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

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

File 9 of 32 : IERC20MetadataUppercase.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IERC20MetadataUppercase {
    function NAME() external view returns (string memory); // solhint-disable-line func-name-mixedcase

    function SYMBOL() external view returns (string memory); // solhint-disable-line func-name-mixedcase
}

File 10 of 32 : IPermit2.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IPermit2 {
    struct PermitDetails {
        // ERC20 token address
        address token;
        // the maximum amount allowed to spend
        uint160 amount;
        // timestamp at which a spender's token allowances become invalid
        uint48 expiration;
        // an incrementing value indexed per owner,token,and spender for each signature
        uint48 nonce;
    }
    /// @notice The permit message signed for a single token allownce
    struct PermitSingle {
        // the permit data for a single token alownce
        PermitDetails details;
        // address permissioned on the allowed tokens
        address spender;
        // deadline on the permit signature
        uint256 sigDeadline;
    }
    /// @notice Packed allowance
    struct PackedAllowance {
        // amount allowed
        uint160 amount;
        // permission expiry
        uint48 expiration;
        // an incrementing value indexed per owner,token,and spender for each signature
        uint48 nonce;
    }

    function transferFrom(address user, address spender, uint160 amount, address token) external;

    function permit(address owner, PermitSingle memory permitSingle, bytes calldata signature) external;

    function allowance(address user, address token, address spender) external view returns (PackedAllowance memory);
}

File 11 of 32 : IWETH.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

interface IWETH is IERC20 {
    event Deposit(address indexed dst, uint256 wad);

    event Withdrawal(address indexed src, uint256 wad);

    function deposit() external payable;

    function withdraw(uint256 amount) external;
}

File 12 of 32 : AddressLib.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

type Address is uint256;

/**
* @dev Library for working with addresses encoded as uint256 values, which can include flags in the highest bits.
*/
library AddressLib {
    uint256 private constant _LOW_160_BIT_MASK = (1 << 160) - 1;

    /**
    * @notice Returns the address representation of a uint256.
    * @param a The uint256 value to convert to an address.
    * @return The address representation of the provided uint256 value.
    */
    function get(Address a) internal pure returns (address) {
        return address(uint160(Address.unwrap(a) & _LOW_160_BIT_MASK));
    }

    /**
    * @notice Checks if a given flag is set for the provided address.
    * @param a The address to check for the flag.
    * @param flag The flag to check for in the provided address.
    * @return True if the provided flag is set in the address, false otherwise.
    */
    function getFlag(Address a, uint256 flag) internal pure returns (bool) {
        return (Address.unwrap(a) & flag) != 0;
    }

    /**
    * @notice Returns a uint32 value stored at a specific bit offset in the provided address.
    * @param a The address containing the uint32 value.
    * @param offset The bit offset at which the uint32 value is stored.
    * @return The uint32 value stored in the address at the specified bit offset.
    */
    function getUint32(Address a, uint256 offset) internal pure returns (uint32) {
        return uint32(Address.unwrap(a) >> offset);
    }

    /**
    * @notice Returns a uint64 value stored at a specific bit offset in the provided address.
    * @param a The address containing the uint64 value.
    * @param offset The bit offset at which the uint64 value is stored.
    * @return The uint64 value stored in the address at the specified bit offset.
    */
    function getUint64(Address a, uint256 offset) internal pure returns (uint64) {
        return uint64(Address.unwrap(a) >> offset);
    }
}

File 13 of 32 : RevertReasonForwarder.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/// @title Revert reason forwarder.
library RevertReasonForwarder {
    /// @dev Forwards latest externall call revert.
    function reRevert() internal pure {
        // bubble up revert reason from latest external call
        assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
            let ptr := mload(0x40)
            returndatacopy(ptr, 0, returndatasize())
            revert(ptr, returndatasize())
        }
    }

    /// @dev Returns latest external call revert reason.
    function reReason() internal pure returns (bytes memory reason) {
        assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
            reason := mload(0x40)
            let length := returndatasize()
            mstore(reason, length)
            returndatacopy(add(reason, 0x20), 0, length)
            mstore(0x40, add(reason, add(0x20, length)))
        }
    }
}

File 14 of 32 : SafeERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol";
import "../interfaces/IDaiLikePermit.sol";
import "../interfaces/IPermit2.sol";
import "../interfaces/IWETH.sol";
import "../libraries/RevertReasonForwarder.sol";

/**
 * @title Implements efficient safe methods for ERC20 interface.
 * @notice Compared to the standard ERC20, this implementation offers several enhancements:
 * 1. more gas-efficient, providing significant savings in transaction costs.
 * 2. support for different permit implementations
 * 3. forceApprove functionality
 * 4. support for WETH deposit and withdraw
 */
library SafeERC20 {
    error SafeTransferFailed();
    error SafeTransferFromFailed();
    error ForceApproveFailed();
    error SafeIncreaseAllowanceFailed();
    error SafeDecreaseAllowanceFailed();
    error SafePermitBadLength();
    error Permit2TransferAmountTooHigh();

    // Uniswap Permit2 address
    address private constant _PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3;
    bytes4 private constant _PERMIT_LENGTH_ERROR = 0x68275857;  // SafePermitBadLength.selector
    uint256 private constant _RAW_CALL_GAS_LIMIT = 5000;

    /**
     * @notice Fetches the balance of a specific ERC20 token held by an account.
     * Consumes less gas then regular `ERC20.balanceOf`.
     * @dev Note that the implementation does not perform dirty bits cleaning, so it is the
     * responsibility of the caller to make sure that the higher 96 bits of the `account` parameter are clean.
     * @param token The IERC20 token contract for which the balance will be fetched.
     * @param account The address of the account whose token balance will be fetched.
     * @return tokenBalance The balance of the specified ERC20 token held by the account.
     */
    function safeBalanceOf(
        IERC20 token,
        address account
    ) internal view returns(uint256 tokenBalance) {
        bytes4 selector = IERC20.balanceOf.selector;
        assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
            mstore(0x00, selector)
            mstore(0x04, account)
            let success := staticcall(gas(), token, 0x00, 0x24, 0x00, 0x20)
            tokenBalance := mload(0)

            if or(iszero(success), lt(returndatasize(), 0x20)) {
                let ptr := mload(0x40)
                returndatacopy(ptr, 0, returndatasize())
                revert(ptr, returndatasize())
            }
        }
    }

    /**
     * @notice Attempts to safely transfer tokens from one address to another.
     * @dev If permit2 is true, uses the Permit2 standard; otherwise uses the standard ERC20 transferFrom.
     * Either requires `true` in return data, or requires target to be smart-contract and empty return data.
     * Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of
     * the caller to make sure that the higher 96 bits of the `from` and `to` parameters are clean.
     * @param token The IERC20 token contract from which the tokens will be transferred.
     * @param from The address from which the tokens will be transferred.
     * @param to The address to which the tokens will be transferred.
     * @param amount The amount of tokens to transfer.
     * @param permit2 If true, uses the Permit2 standard for the transfer; otherwise uses the standard ERC20 transferFrom.
     */
    function safeTransferFromUniversal(
        IERC20 token,
        address from,
        address to,
        uint256 amount,
        bool permit2
    ) internal {
        if (permit2) {
            safeTransferFromPermit2(token, from, to, amount);
        } else {
            safeTransferFrom(token, from, to, amount);
        }
    }

    /**
     * @notice Attempts to safely transfer tokens from one address to another using the ERC20 standard.
     * @dev Either requires `true` in return data, or requires target to be smart-contract and empty return data.
     * Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of
     * the caller to make sure that the higher 96 bits of the `from` and `to` parameters are clean.
     * @param token The IERC20 token contract from which the tokens will be transferred.
     * @param from The address from which the tokens will be transferred.
     * @param to The address to which the tokens will be transferred.
     * @param amount The amount of tokens to transfer.
     */
    function safeTransferFrom(
        IERC20 token,
        address from,
        address to,
        uint256 amount
    ) internal {
        bytes4 selector = token.transferFrom.selector;
        bool success;
        assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
            let data := mload(0x40)

            mstore(data, selector)
            mstore(add(data, 0x04), from)
            mstore(add(data, 0x24), to)
            mstore(add(data, 0x44), amount)
            success := call(gas(), token, 0, data, 100, 0x0, 0x20)
            if success {
                switch returndatasize()
                case 0 {
                    success := gt(extcodesize(token), 0)
                }
                default {
                    success := and(gt(returndatasize(), 31), eq(mload(0), 1))
                }
            }
        }
        if (!success) revert SafeTransferFromFailed();
    }

    /**
     * @notice Attempts to safely transfer tokens from one address to another using the Permit2 standard.
     * @dev Either requires `true` in return data, or requires target to be smart-contract and empty return data.
     * Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of
     * the caller to make sure that the higher 96 bits of the `from` and `to` parameters are clean.
     * @param token The IERC20 token contract from which the tokens will be transferred.
     * @param from The address from which the tokens will be transferred.
     * @param to The address to which the tokens will be transferred.
     * @param amount The amount of tokens to transfer.
     */
    function safeTransferFromPermit2(
        IERC20 token,
        address from,
        address to,
        uint256 amount
    ) internal {
        if (amount > type(uint160).max) revert Permit2TransferAmountTooHigh();
        bytes4 selector = IPermit2.transferFrom.selector;
        bool success;
        assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
            let data := mload(0x40)

            mstore(data, selector)
            mstore(add(data, 0x04), from)
            mstore(add(data, 0x24), to)
            mstore(add(data, 0x44), amount)
            mstore(add(data, 0x64), token)
            success := call(gas(), _PERMIT2, 0, data, 0x84, 0x0, 0x0)
            if success {
                success := gt(extcodesize(_PERMIT2), 0)
            }
        }
        if (!success) revert SafeTransferFromFailed();
    }

    /**
     * @notice Attempts to safely transfer tokens to another address.
     * @dev Either requires `true` in return data, or requires target to be smart-contract and empty return data.
     * Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of
     * the caller to make sure that the higher 96 bits of the `to` parameter are clean.
     * @param token The IERC20 token contract from which the tokens will be transferred.
     * @param to The address to which the tokens will be transferred.
     * @param value The amount of tokens to transfer.
     */
    function safeTransfer(
        IERC20 token,
        address to,
        uint256 value
    ) internal {
        if (!_makeCall(token, token.transfer.selector, to, value)) {
            revert SafeTransferFailed();
        }
    }

    /**
     * @notice Attempts to approve a spender to spend a certain amount of tokens.
     * @dev If `approve(from, to, amount)` fails, it tries to set the allowance to zero, and retries the `approve` call.
     * Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of
     * the caller to make sure that the higher 96 bits of the `spender` parameter are clean.
     * @param token The IERC20 token contract on which the call will be made.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     */
    function forceApprove(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        if (!_makeCall(token, token.approve.selector, spender, value)) {
            if (
                !_makeCall(token, token.approve.selector, spender, 0) ||
                !_makeCall(token, token.approve.selector, spender, value)
            ) {
                revert ForceApproveFailed();
            }
        }
    }

    /**
     * @notice Safely increases the allowance of a spender.
     * @dev Increases with safe math check. Checks if the increased allowance will overflow, if yes, then it reverts the transaction.
     * Then uses `forceApprove` to increase the allowance.
     * Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of
     * the caller to make sure that the higher 96 bits of the `spender` parameter are clean.
     * @param token The IERC20 token contract on which the call will be made.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to increase the allowance by.
     */
    function safeIncreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        uint256 allowance = token.allowance(address(this), spender);
        if (value > type(uint256).max - allowance) revert SafeIncreaseAllowanceFailed();
        forceApprove(token, spender, allowance + value);
    }

    /**
     * @notice Safely decreases the allowance of a spender.
     * @dev Decreases with safe math check. Checks if the decreased allowance will underflow, if yes, then it reverts the transaction.
     * Then uses `forceApprove` to increase the allowance.
     * Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of
     * the caller to make sure that the higher 96 bits of the `spender` parameter are clean.
     * @param token The IERC20 token contract on which the call will be made.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to decrease the allowance by.
     */
    function safeDecreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        uint256 allowance = token.allowance(address(this), spender);
        if (value > allowance) revert SafeDecreaseAllowanceFailed();
        forceApprove(token, spender, allowance - value);
    }

    /**
     * @notice Attempts to execute the `permit` function on the provided token with the sender and contract as parameters.
     * Permit type is determined automatically based on permit calldata (IERC20Permit, IDaiLikePermit, and IPermit2).
     * @dev Wraps `tryPermit` function and forwards revert reason if permit fails.
     * @param token The IERC20 token to execute the permit function on.
     * @param permit The permit data to be used in the function call.
     */
    function safePermit(IERC20 token, bytes calldata permit) internal {
        if (!tryPermit(token, msg.sender, address(this), permit)) RevertReasonForwarder.reRevert();
    }

    /**
     * @notice Attempts to execute the `permit` function on the provided token with custom owner and spender parameters.
     * Permit type is determined automatically based on permit calldata (IERC20Permit, IDaiLikePermit, and IPermit2).
     * @dev Wraps `tryPermit` function and forwards revert reason if permit fails.
     * Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of
     * the caller to make sure that the higher 96 bits of the `owner` and `spender` parameters are clean.
     * @param token The IERC20 token to execute the permit function on.
     * @param owner The owner of the tokens for which the permit is made.
     * @param spender The spender allowed to spend the tokens by the permit.
     * @param permit The permit data to be used in the function call.
     */
    function safePermit(IERC20 token, address owner, address spender, bytes calldata permit) internal {
        if (!tryPermit(token, owner, spender, permit)) RevertReasonForwarder.reRevert();
    }

    /**
     * @notice Attempts to execute the `permit` function on the provided token with the sender and contract as parameters.
     * @dev Invokes `tryPermit` with sender as owner and contract as spender.
     * @param token The IERC20 token to execute the permit function on.
     * @param permit The permit data to be used in the function call.
     * @return success Returns true if the permit function was successfully executed, false otherwise.
     */
    function tryPermit(IERC20 token, bytes calldata permit) internal returns(bool success) {
        return tryPermit(token, msg.sender, address(this), permit);
    }

    /**
     * @notice The function attempts to call the permit function on a given ERC20 token.
     * @dev The function is designed to support a variety of permit functions, namely: IERC20Permit, IDaiLikePermit, and IPermit2.
     * It accommodates both Compact and Full formats of these permit types.
     * Please note, it is expected that the `expiration` parameter for the compact Permit2 and the `deadline` parameter
     * for the compact Permit are to be incremented by one before invoking this function. This approach is motivated by
     * gas efficiency considerations; as the unlimited expiration period is likely to be the most common scenario, and
     * zeros are cheaper to pass in terms of gas cost. Thus, callers should increment the expiration or deadline by one
     * before invocation for optimized performance.
     * Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of
     * the caller to make sure that the higher 96 bits of the `owner` and `spender` parameters are clean.
     * @param token The address of the ERC20 token on which to call the permit function.
     * @param owner The owner of the tokens. This address should have signed the off-chain permit.
     * @param spender The address which will be approved for transfer of tokens.
     * @param permit The off-chain permit data, containing different fields depending on the type of permit function.
     * @return success A boolean indicating whether the permit call was successful.
     */
    function tryPermit(IERC20 token, address owner, address spender, bytes calldata permit) internal returns(bool success) {
        // load function selectors for different permit standards
        bytes4 permitSelector = IERC20Permit.permit.selector;
        bytes4 daiPermitSelector = IDaiLikePermit.permit.selector;
        bytes4 permit2Selector = IPermit2.permit.selector;
        assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
            let ptr := mload(0x40)

            // Switch case for different permit lengths, indicating different permit standards
            switch permit.length
            // Compact IERC20Permit
            case 100 {
                mstore(ptr, permitSelector)     // store selector
                mstore(add(ptr, 0x04), owner)   // store owner
                mstore(add(ptr, 0x24), spender) // store spender

                // Compact IERC20Permit.permit(uint256 value, uint32 deadline, uint256 r, uint256 vs)
                {  // stack too deep
                    let deadline := shr(224, calldataload(add(permit.offset, 0x20))) // loads permit.offset 0x20..0x23
                    let vs := calldataload(add(permit.offset, 0x44))                 // loads permit.offset 0x44..0x63

                    calldatacopy(add(ptr, 0x44), permit.offset, 0x20)            // store value     = copy permit.offset 0x00..0x19
                    mstore(add(ptr, 0x64), sub(deadline, 1))                     // store deadline  = deadline - 1
                    mstore(add(ptr, 0x84), add(27, shr(255, vs)))                // store v         = most significant bit of vs + 27 (27 or 28)
                    calldatacopy(add(ptr, 0xa4), add(permit.offset, 0x24), 0x20) // store r         = copy permit.offset 0x24..0x43
                    mstore(add(ptr, 0xc4), shr(1, shl(1, vs)))                   // store s         = vs without most significant bit
                }
                // IERC20Permit.permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
                success := call(gas(), token, 0, ptr, 0xe4, 0, 0)
            }
            // Compact IDaiLikePermit
            case 72 {
                mstore(ptr, daiPermitSelector)  // store selector
                mstore(add(ptr, 0x04), owner)   // store owner
                mstore(add(ptr, 0x24), spender) // store spender

                // Compact IDaiLikePermit.permit(uint32 nonce, uint32 expiry, uint256 r, uint256 vs)
                {  // stack too deep
                    let expiry := shr(224, calldataload(add(permit.offset, 0x04))) // loads permit.offset 0x04..0x07
                    let vs := calldataload(add(permit.offset, 0x28))               // loads permit.offset 0x28..0x47

                    mstore(add(ptr, 0x44), shr(224, calldataload(permit.offset))) // store nonce   = copy permit.offset 0x00..0x03
                    mstore(add(ptr, 0x64), sub(expiry, 1))                        // store expiry  = expiry - 1
                    mstore(add(ptr, 0x84), true)                                  // store allowed = true
                    mstore(add(ptr, 0xa4), add(27, shr(255, vs)))                 // store v       = most significant bit of vs + 27 (27 or 28)
                    calldatacopy(add(ptr, 0xc4), add(permit.offset, 0x08), 0x20)  // store r       = copy permit.offset 0x08..0x27
                    mstore(add(ptr, 0xe4), shr(1, shl(1, vs)))                    // store s       = vs without most significant bit
                }
                // IDaiLikePermit.permit(address holder, address spender, uint256 nonce, uint256 expiry, bool allowed, uint8 v, bytes32 r, bytes32 s)
                success := call(gas(), token, 0, ptr, 0x104, 0, 0)
            }
            // IERC20Permit
            case 224 {
                mstore(ptr, permitSelector)
                calldatacopy(add(ptr, 0x04), permit.offset, permit.length) // copy permit calldata
                // IERC20Permit.permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
                success := call(gas(), token, 0, ptr, 0xe4, 0, 0)
            }
            // IDaiLikePermit
            case 256 {
                mstore(ptr, daiPermitSelector)
                calldatacopy(add(ptr, 0x04), permit.offset, permit.length) // copy permit calldata
                // IDaiLikePermit.permit(address holder, address spender, uint256 nonce, uint256 expiry, bool allowed, uint8 v, bytes32 r, bytes32 s)
                success := call(gas(), token, 0, ptr, 0x104, 0, 0)
            }
            // Compact IPermit2
            case 96 {
                // Compact IPermit2.permit(uint160 amount, uint32 expiration, uint32 nonce, uint32 sigDeadline, uint256 r, uint256 vs)
                mstore(ptr, permit2Selector)  // store selector
                mstore(add(ptr, 0x04), owner) // store owner
                mstore(add(ptr, 0x24), token) // store token

                calldatacopy(add(ptr, 0x50), permit.offset, 0x14)             // store amount = copy permit.offset 0x00..0x13
                // and(0xffffffffffff, ...) - conversion to uint48
                mstore(add(ptr, 0x64), and(0xffffffffffff, sub(shr(224, calldataload(add(permit.offset, 0x14))), 1))) // store expiration = ((permit.offset 0x14..0x17 - 1) & 0xffffffffffff)
                mstore(add(ptr, 0x84), shr(224, calldataload(add(permit.offset, 0x18)))) // store nonce = copy permit.offset 0x18..0x1b
                mstore(add(ptr, 0xa4), spender)                               // store spender
                // and(0xffffffffffff, ...) - conversion to uint48
                mstore(add(ptr, 0xc4), and(0xffffffffffff, sub(shr(224, calldataload(add(permit.offset, 0x1c))), 1))) // store sigDeadline = ((permit.offset 0x1c..0x1f - 1) & 0xffffffffffff)
                mstore(add(ptr, 0xe4), 0x100)                                 // store offset = 256
                mstore(add(ptr, 0x104), 0x40)                                 // store length = 64
                calldatacopy(add(ptr, 0x124), add(permit.offset, 0x20), 0x20) // store r      = copy permit.offset 0x20..0x3f
                calldatacopy(add(ptr, 0x144), add(permit.offset, 0x40), 0x20) // store vs     = copy permit.offset 0x40..0x5f
                // IPermit2.permit(address owner, PermitSingle calldata permitSingle, bytes calldata signature)
                success := call(gas(), _PERMIT2, 0, ptr, 0x164, 0, 0)
            }
            // IPermit2
            case 352 {
                mstore(ptr, permit2Selector)
                calldatacopy(add(ptr, 0x04), permit.offset, permit.length) // copy permit calldata
                // IPermit2.permit(address owner, PermitSingle calldata permitSingle, bytes calldata signature)
                success := call(gas(), _PERMIT2, 0, ptr, 0x164, 0, 0)
            }
            // Unknown
            default {
                mstore(ptr, _PERMIT_LENGTH_ERROR)
                revert(ptr, 4)
            }
        }
    }

    /**
     * @dev Executes a low level call to a token contract, making it resistant to reversion and erroneous boolean returns.
     * @param token The IERC20 token contract on which the call will be made.
     * @param selector The function signature that is to be called on the token contract.
     * @param to The address to which the token amount will be transferred.
     * @param amount The token amount to be transferred.
     * @return success A boolean indicating if the call was successful. Returns 'true' on success and 'false' on failure.
     * In case of success but no returned data, validates that the contract code exists.
     * In case of returned data, ensures that it's a boolean `true`.
     */
    function _makeCall(
        IERC20 token,
        bytes4 selector,
        address to,
        uint256 amount
    ) private returns (bool success) {
        assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
            let data := mload(0x40)

            mstore(data, selector)
            mstore(add(data, 0x04), to)
            mstore(add(data, 0x24), amount)
            success := call(gas(), token, 0, data, 0x44, 0x0, 0x20)
            if success {
                switch returndatasize()
                case 0 {
                    success := gt(extcodesize(token), 0)
                }
                default {
                    success := and(gt(returndatasize(), 31), eq(mload(0), 1))
                }
            }
        }
    }

    /**
     * @notice Safely deposits a specified amount of Ether into the IWETH contract. Consumes less gas then regular `IWETH.deposit`.
     * @param weth The IWETH token contract.
     * @param amount The amount of Ether to deposit into the IWETH contract.
     */
    function safeDeposit(IWETH weth, uint256 amount) internal {
        if (amount > 0) {
            bytes4 selector = IWETH.deposit.selector;
            assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
                mstore(0, selector)
                if iszero(call(gas(), weth, amount, 0, 4, 0, 0)) {
                    let ptr := mload(0x40)
                    returndatacopy(ptr, 0, returndatasize())
                    revert(ptr, returndatasize())
                }
            }
        }
    }

    /**
     * @notice Safely withdraws a specified amount of wrapped Ether from the IWETH contract. Consumes less gas then regular `IWETH.withdraw`.
     * @dev Uses inline assembly to interact with the IWETH contract.
     * @param weth The IWETH token contract.
     * @param amount The amount of wrapped Ether to withdraw from the IWETH contract.
     */
    function safeWithdraw(IWETH weth, uint256 amount) internal {
        bytes4 selector = IWETH.withdraw.selector;
        assembly ("memory-safe") {  // solhint-disable-line no-inline-assembly
            mstore(0, selector)
            mstore(4, amount)
            if iszero(call(gas(), weth, 0, 0, 0x24, 0, 0)) {
                let ptr := mload(0x40)
                returndatacopy(ptr, 0, returndatasize())
                revert(ptr, returndatasize())
            }
        }
    }

    /**
     * @notice Safely withdraws a specified amount of wrapped Ether from the IWETH contract to a specified recipient.
     * Consumes less gas then regular `IWETH.withdraw`.
     * @param weth The IWETH token contract.
     * @param amount The amount of wrapped Ether to withdraw from the IWETH contract.
     * @param to The recipient of the withdrawn Ether.
     */
    function safeWithdrawTo(IWETH weth, uint256 amount, address to) internal {
        safeWithdraw(weth, amount);
        if (to != address(this)) {
            assembly ("memory-safe") {  // solhint-disable-line no-inline-assembly
                if iszero(call(_RAW_CALL_GAS_LIMIT, to, amount, 0, 0, 0, 0)) {
                    let ptr := mload(0x40)
                    returndatacopy(ptr, 0, returndatasize())
                    revert(ptr, returndatasize())
                }
            }
        }
    }
}

File 15 of 32 : StringUtil.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/// @title Library with gas-efficient string operations
library StringUtil {
    function toHex(uint256 value) internal pure returns (string memory) {
        return toHex(abi.encodePacked(value));
    }

    function toHex(address value) internal pure returns (string memory) {
        return toHex(abi.encodePacked(value));
    }

    /// @dev this is the assembly adaptation of highly optimized toHex16 code from Mikhail Vladimirov
    /// https://stackoverflow.com/a/69266989
    function toHex(bytes memory data) internal pure returns (string memory result) {
        assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
            function _toHex16(input) -> output {
                output := or(
                    and(input, 0xFFFFFFFFFFFFFFFF000000000000000000000000000000000000000000000000),
                    shr(64, and(input, 0x0000000000000000FFFFFFFFFFFFFFFF00000000000000000000000000000000))
                )
                output := or(
                    and(output, 0xFFFFFFFF000000000000000000000000FFFFFFFF000000000000000000000000),
                    shr(32, and(output, 0x00000000FFFFFFFF000000000000000000000000FFFFFFFF0000000000000000))
                )
                output := or(
                    and(output, 0xFFFF000000000000FFFF000000000000FFFF000000000000FFFF000000000000),
                    shr(16, and(output, 0x0000FFFF000000000000FFFF000000000000FFFF000000000000FFFF00000000))
                )
                output := or(
                    and(output, 0xFF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000),
                    shr(8, and(output, 0x00FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000))
                )
                output := or(
                    shr(4, and(output, 0xF000F000F000F000F000F000F000F000F000F000F000F000F000F000F000F000)),
                    shr(8, and(output, 0x0F000F000F000F000F000F000F000F000F000F000F000F000F000F000F000F00))
                )
                output := add(
                    add(0x3030303030303030303030303030303030303030303030303030303030303030, output),
                    mul(
                        and(
                            shr(4, add(output, 0x0606060606060606060606060606060606060606060606060606060606060606)),
                            0x0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F
                        ),
                        7 // Change 7 to 39 for lower case output
                    )
                )
            }

            result := mload(0x40)
            let length := mload(data)
            let resultLength := shl(1, length)
            let toPtr := add(result, 0x22) // 32 bytes for length + 2 bytes for '0x'
            mstore(0x40, add(toPtr, resultLength)) // move free memory pointer
            mstore(add(result, 2), 0x3078) // 0x3078 is right aligned so we write to `result + 2`
            // to store the last 2 bytes in the beginning of the string
            mstore(result, add(resultLength, 2)) // extra 2 bytes for '0x'

            for {
                let fromPtr := add(data, 0x20)
                let endPtr := add(fromPtr, length)
            } lt(fromPtr, endPtr) {
                fromPtr := add(fromPtr, 0x20)
            } {
                let rawData := mload(fromPtr)
                let hexData := _toHex16(rawData)
                mstore(toPtr, hexData)
                toPtr := add(toPtr, 0x20)
                hexData := _toHex16(shl(128, rawData))
                mstore(toPtr, hexData)
                toPtr := add(toPtr, 0x20)
            }
        }
    }
}

File 16 of 32 : UniERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "../interfaces/IERC20MetadataUppercase.sol";
import "./SafeERC20.sol";
import "./StringUtil.sol";

/// @title Library, which allows usage of ETH as ERC20 and ERC20 itself. Uses SafeERC20 library for ERC20 interface.
library UniERC20 {
    using SafeERC20 for IERC20;

    error InsufficientBalance();
    error ApproveCalledOnETH();
    error NotEnoughValue();
    error FromIsNotSender();
    error ToIsNotThis();
    error ETHTransferFailed();

    uint256 private constant _RAW_CALL_GAS_LIMIT = 5000;
    IERC20 private constant _ETH_ADDRESS = IERC20(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
    IERC20 private constant _ZERO_ADDRESS = IERC20(address(0));

    /// @dev Returns true if `token` is ETH.
    function isETH(IERC20 token) internal pure returns (bool) {
        return (token == _ZERO_ADDRESS || token == _ETH_ADDRESS);
    }

    /// @dev Returns `account` ERC20 `token` balance.
    function uniBalanceOf(IERC20 token, address account) internal view returns (uint256) {
        if (isETH(token)) {
            return account.balance;
        } else {
            return token.balanceOf(account);
        }
    }

    /// @dev `token` transfer `to` `amount`.
    /// Note that this function does nothing in case of zero amount.
    function uniTransfer(
        IERC20 token,
        address payable to,
        uint256 amount
    ) internal {
        if (amount > 0) {
            if (isETH(token)) {
                if (address(this).balance < amount) revert InsufficientBalance();
                // solhint-disable-next-line avoid-low-level-calls
                (bool success, ) = to.call{value: amount, gas: _RAW_CALL_GAS_LIMIT}("");
                if (!success) revert ETHTransferFailed();
            } else {
                token.safeTransfer(to, amount);
            }
        }
    }

    /// @dev `token` transfer `from` `to` `amount`.
    /// Note that this function does nothing in case of zero amount.
    function uniTransferFrom(
        IERC20 token,
        address payable from,
        address to,
        uint256 amount
    ) internal {
        if (amount > 0) {
            if (isETH(token)) {
                if (msg.value < amount) revert NotEnoughValue();
                if (from != msg.sender) revert FromIsNotSender();
                if (to != address(this)) revert ToIsNotThis();
                if (msg.value > amount) {
                    // Return remainder if exist
                    unchecked {
                        // solhint-disable-next-line avoid-low-level-calls
                        (bool success, ) = from.call{value: msg.value - amount, gas: _RAW_CALL_GAS_LIMIT}("");
                        if (!success) revert ETHTransferFailed();
                    }
                }
            } else {
                token.safeTransferFrom(from, to, amount);
            }
        }
    }

    /// @dev Returns `token` symbol from ERC20 metadata.
    function uniSymbol(IERC20 token) internal view returns (string memory) {
        return _uniDecode(token, IERC20Metadata.symbol.selector, IERC20MetadataUppercase.SYMBOL.selector);
    }

    /// @dev Returns `token` name from ERC20 metadata.
    function uniName(IERC20 token) internal view returns (string memory) {
        return _uniDecode(token, IERC20Metadata.name.selector, IERC20MetadataUppercase.NAME.selector);
    }

    /// @dev Reverts if `token` is ETH, otherwise performs ERC20 forceApprove.
    function uniApprove(
        IERC20 token,
        address to,
        uint256 amount
    ) internal {
        if (isETH(token)) revert ApproveCalledOnETH();

        token.forceApprove(to, amount);
    }

    /// @dev 20K gas is provided to account for possible implementations of name/symbol
    /// (token implementation might be behind proxy or store the value in storage)
    function _uniDecode(
        IERC20 token,
        bytes4 lowerCaseSelector,
        bytes4 upperCaseSelector
    ) private view returns (string memory result) {
        if (isETH(token)) {
            return "ETH";
        }

        (bool success, bytes memory data) = address(token).staticcall{gas: 20000}(
            abi.encodeWithSelector(lowerCaseSelector)
        );
        if (!success) {
            (success, data) = address(token).staticcall{gas: 20000}(abi.encodeWithSelector(upperCaseSelector));
        }

        if (success && data.length >= 0x40) {
            (uint256 offset, uint256 len) = abi.decode(data, (uint256, uint256));
            /*
                return data is padded up to 32 bytes with ABI encoder also sometimes
                there is extra 32 bytes of zeros padded in the end:
                https://github.com/ethereum/solidity/issues/10170
                because of that we can't check for equality and instead check
                that overall data length is greater or equal than string length + extra 64 bytes
            */
            if (offset == 0x20 && data.length >= 0x40 + len) {
                assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
                    result := add(data, 0x40)
                }
                return result;
            }
        }
        if (success && data.length == 32) {
            uint256 len = 0;
            while (len < data.length && data[len] >= 0x20 && data[len] <= 0x7E) {
                unchecked {
                    len++;
                }
            }

            if (len > 0) {
                assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
                    mstore(data, len)
                }
                return string(data);
            }
        }

        return StringUtil.toHex(address(token));
    }
}

File 17 of 32 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

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

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

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

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

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

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

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

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

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

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

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

File 18 of 32 : IERC20Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.20;

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

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

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

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

File 19 of 32 : IERC20Permit.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 *
 * ==== Security Considerations
 *
 * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
 * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
 * considered as an intention to spend the allowance in any specific way. The second is that because permits have
 * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
 * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
 * generally recommended is:
 *
 * ```solidity
 * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
 *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
 *     doThing(..., value);
 * }
 *
 * function doThing(..., uint256 value) public {
 *     token.safeTransferFrom(msg.sender, address(this), value);
 *     ...
 * }
 * ```
 *
 * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
 * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
 * {SafeERC20-safeTransferFrom}).
 *
 * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
 * contracts should have entry points that don't rely on permit.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     *
     * CAUTION: See Security Considerations above.
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

File 20 of 32 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

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

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

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

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

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

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

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

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

File 21 of 32 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

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

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

File 22 of 32 : Math.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)

pragma solidity ^0.8.20;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Muldiv operation overflow.
     */
    error MathOverflowedMulDiv();

    enum Rounding {
        Floor, // Toward negative infinity
        Ceil, // Toward positive infinity
        Trunc, // Toward zero
        Expand // Away from zero
    }

    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, with an overflow flag.
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

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

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

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

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds towards infinity instead
     * of rounding towards zero.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        if (b == 0) {
            // Guarantee the same behavior as in a regular Solidity division.
            return a / b;
        }

        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

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

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                // The surrounding unchecked block does not change this fact.
                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            if (denominator <= prod1) {
                revert MathOverflowedMulDiv();
            }

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

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

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

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

            uint256 twos = denominator & (0 - denominator);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    /**
     * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
     */
    function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
        return uint8(rounding) % 2 == 1;
    }
}

File 23 of 32 : BaseExtension.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.23;

import { Math } from "@openzeppelin/contracts/utils/math/Math.sol";
import { IOrderMixin } from "@1inch/limit-order-protocol-contract/contracts/interfaces/IOrderMixin.sol";
import { IPostInteraction } from "@1inch/limit-order-protocol-contract/contracts/interfaces/IPostInteraction.sol";
import { IPreInteraction } from "@1inch/limit-order-protocol-contract/contracts/interfaces/IPreInteraction.sol";
import { IAmountGetter } from "@1inch/limit-order-protocol-contract/contracts/interfaces/IAmountGetter.sol";

/**
 * @title Base Extension contract
 * @notice Contract to define the basic functionality for the limit orders settlement.
 */
contract BaseExtension is IPreInteraction, IPostInteraction, IAmountGetter {
    error OnlyLimitOrderProtocol();

    uint256 private constant _BASE_POINTS = 10_000_000; // 100%
    uint256 private constant _GAS_PRICE_BASE = 1_000_000; // 1000 means 1 Gwei

    address private immutable _LIMIT_ORDER_PROTOCOL;

    /// @dev Modifier to check if the caller is the limit order protocol contract.
    modifier onlyLimitOrderProtocol {
        if (msg.sender != _LIMIT_ORDER_PROTOCOL) revert OnlyLimitOrderProtocol();
        _;
    }

    /**
     * @notice Initializes the contract.
     * @param limitOrderProtocol The limit order protocol contract.
     */
    constructor(address limitOrderProtocol) {
        _LIMIT_ORDER_PROTOCOL = limitOrderProtocol;
    }

    /**
     * See {IAmountGetter-getMakingAmount}
     */
    function getMakingAmount(
        IOrderMixin.Order calldata order,
        bytes calldata /* extension */,
        bytes32 /* orderHash */,
        address /* taker */,
        uint256 takingAmount,
        uint256 /* remainingMakingAmount */,
        bytes calldata extraData
    ) external view returns (uint256) {
        uint256 rateBump = _getRateBump(extraData);
        return Math.mulDiv(order.makingAmount, takingAmount * _BASE_POINTS, order.takingAmount * (_BASE_POINTS + rateBump));
    }

    /**
     * See {IAmountGetter-getTakingAmount}
     */
    function getTakingAmount(
        IOrderMixin.Order calldata order,
        bytes calldata /* extension */,
        bytes32 /* orderHash */,
        address /* taker */,
        uint256 makingAmount,
        uint256 /* remainingMakingAmount */,
        bytes calldata extraData
    ) external view returns (uint256) {
        uint256 rateBump = _getRateBump(extraData);
        return Math.mulDiv(order.takingAmount, makingAmount * (_BASE_POINTS + rateBump), order.makingAmount * _BASE_POINTS, Math.Rounding.Ceil);
    }

    /**
     * See {IPreInteraction-preInteraction}
     */
    function preInteraction(
        IOrderMixin.Order calldata order,
        bytes calldata extension,
        bytes32 orderHash,
        address taker,
        uint256 makingAmount,
        uint256 takingAmount,
        uint256 remainingMakingAmount,
        bytes calldata extraData
    ) external onlyLimitOrderProtocol {
        _preInteraction(order, extension, orderHash, taker, makingAmount, takingAmount, remainingMakingAmount, extraData);
    }

    /**
     * See {IPostInteraction-postInteraction}
     */
    function postInteraction(
        IOrderMixin.Order calldata order,
        bytes calldata extension,
        bytes32 orderHash,
        address taker,
        uint256 makingAmount,
        uint256 takingAmount,
        uint256 remainingMakingAmount,
        bytes calldata extraData
    ) external onlyLimitOrderProtocol {
        _postInteraction(order, extension, orderHash, taker, makingAmount, takingAmount, remainingMakingAmount, extraData);
    }

    function _preInteraction(
        IOrderMixin.Order calldata order,
        bytes calldata extension,
        bytes32 orderHash,
        address taker,
        uint256 makingAmount,
        uint256 takingAmount,
        uint256 remainingMakingAmount,
        bytes calldata extraData
    ) internal virtual {}

    function _postInteraction(
        IOrderMixin.Order calldata order,
        bytes calldata extension,
        bytes32 orderHash,
        address taker,
        uint256 makingAmount,
        uint256 takingAmount,
        uint256 remainingMakingAmount,
        bytes calldata extraData
    ) internal virtual {}

    /**
     * @dev Parses auction rate bump data from the `auctionDetails` field.
     * `gasBumpEstimate` and `gasPriceEstimate` are used to estimate the transaction costs
     * which are then offset from the auction rate bump.
     * @param auctionDetails AuctionDetails is a tightly packed struct of the following format:
     * ```
     * struct AuctionDetails {
     *     bytes3 gasBumpEstimate;
     *     bytes4 gasPriceEstimate;
     *     bytes4 auctionStartTime;
     *     bytes3 auctionDuration;
     *     bytes3 initialRateBump;
     *     (bytes3,bytes2)[N] pointsAndTimeDeltas;
     * }
     * ```
     * @return rateBump The rate bump.
     */
    function _getRateBump(bytes calldata auctionDetails) private view returns (uint256) {
        unchecked {
            uint256 gasBumpEstimate = uint24(bytes3(auctionDetails[0:3]));
            uint256 gasPriceEstimate = uint32(bytes4(auctionDetails[3:7]));
            uint256 gasBump = gasBumpEstimate == 0 || gasPriceEstimate == 0 ? 0 : gasBumpEstimate * block.basefee / gasPriceEstimate / _GAS_PRICE_BASE;
            uint256 auctionStartTime = uint32(bytes4(auctionDetails[7:11]));
            uint256 auctionFinishTime = auctionStartTime + uint24(bytes3(auctionDetails[11:14]));
            uint256 initialRateBump = uint24(bytes3(auctionDetails[14:17]));
            uint256 auctionBump = _getAuctionBump(auctionStartTime, auctionFinishTime, initialRateBump, auctionDetails[17:]);
            return auctionBump > gasBump ? auctionBump - gasBump : 0;
        }
    }

    /**
     * @dev Calculates auction price bump. Auction is represented as a piecewise linear function with `N` points.
     * Each point is represented as a pair of `(rateBump, timeDelta)`, where `rateBump` is the
     * rate bump in basis points and `timeDelta` is the time delta in seconds.
     * The rate bump is interpolated linearly between the points.
     * The last point is assumed to be `(0, auctionDuration)`.
     * @param auctionStartTime The time when the auction starts.
     * @param auctionFinishTime The time when the auction finishes.
     * @param initialRateBump The initial rate bump.
     * @param pointsAndTimeDeltas The points and time deltas structure.
     * @return The rate bump at the current time.
     */
    function _getAuctionBump(uint256 auctionStartTime, uint256 auctionFinishTime, uint256 initialRateBump, bytes calldata pointsAndTimeDeltas) private view returns (uint256) {
        unchecked {
            if (block.timestamp <= auctionStartTime) {
                return initialRateBump;
            } else if (block.timestamp >= auctionFinishTime) {
                return 0;
            }

            uint256 currentPointTime = auctionStartTime;
            uint256 currentRateBump = initialRateBump;

            while (pointsAndTimeDeltas.length > 0) {
                uint256 nextRateBump = uint24(bytes3(pointsAndTimeDeltas[:3]));
                uint256 nextPointTime = currentPointTime + uint16(bytes2(pointsAndTimeDeltas[3:5]));
                if (block.timestamp <= nextPointTime) {
                    return ((block.timestamp - currentPointTime) * nextRateBump + (nextPointTime - block.timestamp) * currentRateBump) / (nextPointTime - currentPointTime);
                }
                currentRateBump = nextRateBump;
                currentPointTime = nextPointTime;
                pointsAndTimeDeltas = pointsAndTimeDeltas[5:];
            }
            return (auctionFinishTime - block.timestamp) * currentRateBump / (auctionFinishTime - currentPointTime);
        }
    }
}

File 24 of 32 : ExtensionLib.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @title Extension Library
 * @notice Library to retrieve data from the bitmap.
 */
library ExtensionLib {
    bytes1 private constant _RESOLVER_FEE_FLAG = 0x01;
    bytes1 private constant _INTEGRATOR_FEE_FLAG = 0x02;
    bytes1 private constant _CUSTOM_RECEIVER_FLAG = 0x04;
    uint256 private constant _WHITELIST_SHIFT = 3;

    /**
     * @notice Checks if the resolver fee is enabled
     * @param extraData Data to be processed in the extension
     * @return True if the resolver fee is enabled
     */
    function resolverFeeEnabled(bytes calldata extraData) internal pure returns (bool) {
        return extraData[extraData.length - 1] & _RESOLVER_FEE_FLAG == _RESOLVER_FEE_FLAG;
    }

    /**
     * @notice Checks if the integrator fee is enabled
     * @param extraData Data to be processed in the extension
     * @return True if the integrator fee is enabled
     */
    function integratorFeeEnabled(bytes calldata extraData) internal pure returns (bool) {
        return extraData[extraData.length - 1] & _INTEGRATOR_FEE_FLAG == _INTEGRATOR_FEE_FLAG;
    }

    /**
     * @notice Checks if the custom receiver is enabled
     * @param extraData Data to be processed in the extension
     * @return True if the custom receiver is specified
     */
    function hasCustomReceiver(bytes calldata extraData) internal pure returns (bool) {
        return extraData[extraData.length - 1] & _CUSTOM_RECEIVER_FLAG == _CUSTOM_RECEIVER_FLAG;
    }

    /**
     * @notice Gets the number of resolvers in the whitelist
     * @param extraData Data to be processed in the extension
     * @return The number of resolvers in the whitelist
     */
    function resolversCount(bytes calldata extraData) internal pure returns (uint256) {
        return uint8(extraData[extraData.length - 1]) >> _WHITELIST_SHIFT;
    }
}

File 25 of 32 : IntegratorFeeExtension.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.23;

import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { IOrderMixin } from "@1inch/limit-order-protocol-contract/contracts/interfaces/IOrderMixin.sol";
import { MakerTraits, MakerTraitsLib } from "@1inch/limit-order-protocol-contract/contracts/libraries/MakerTraitsLib.sol";
import { SafeERC20 } from "@1inch/solidity-utils/contracts/libraries/SafeERC20.sol";
import { Address, AddressLib } from "@1inch/solidity-utils/contracts/libraries/AddressLib.sol";
import { UniERC20 } from "@1inch/solidity-utils/contracts/libraries/UniERC20.sol";
import { BaseExtension } from "./BaseExtension.sol";
import { ExtensionLib } from "./ExtensionLib.sol";

/**
 * @title Integrator Fee Extension
 * @notice Abstract contract designed to integrate fee processing within the post-interaction phase of order execution.
 */
abstract contract IntegratorFeeExtension is BaseExtension, Ownable {
    using SafeERC20 for IERC20;
    using AddressLib for Address;
    using ExtensionLib for bytes;
    using MakerTraitsLib for MakerTraits;
    using UniERC20 for IERC20;

    /**
     * @dev Eth transfer failed. The target fallback may have reverted.
     */
    error EthTransferFailed();

    /// @dev Allows fees in range [1e-5, 0.65536]
    uint256 private constant _FEE_BASE = 1e5;

    address private immutable _WETH;

    constructor(address weth) {
        _WETH = weth;
    }

    /**
     * @notice Fallback function to receive ETH.
     */
    receive() external payable {}

    /**
     * @param extraData Structured data of length n bytes, segmented as follows:
     * [0:2]   - Fee percentage in basis points.
     * [2:22]  - Integrator address.
     * [22:42] - Custom receiver address.
     * [42:n]  - ExtraData for other extensions, not utilized by this integration fee extension.
     * [n] - Bitmap indicating usage flags, where `xxxx xx1x` signifies integration fee usage. Other bits in this bitmap are not used by this extension.
     */
    function _postInteraction(
        IOrderMixin.Order calldata order,
        bytes calldata extension,
        bytes32 orderHash,
        address taker,
        uint256 makingAmount,
        uint256 takingAmount,
        uint256 remainingMakingAmount,
        bytes calldata extraData
    ) internal virtual override {
        if (extraData.integratorFeeEnabled()) {
            uint256 fee = takingAmount * uint256(uint16(bytes2(extraData))) / _FEE_BASE;
            address feeRecipient = address(bytes20(extraData[2:22]));
            extraData = extraData[22:];

            address receiver = order.maker.get();
            if (extraData.hasCustomReceiver()) {
                receiver = address(bytes20(extraData));
                extraData = extraData[20:];
            }

            bool isEth = order.takerAsset.get() == address(_WETH) && order.makerTraits.unwrapWeth();

            if (isEth) {
                if (fee > 0) {
                    _sendEth(feeRecipient, fee);
                }
                unchecked {
                    _sendEth(receiver, takingAmount - fee);
                }
            } else {
                if (fee > 0) {
                    IERC20(order.takerAsset.get()).safeTransfer(feeRecipient, fee);
                }
                unchecked {
                    IERC20(order.takerAsset.get()).safeTransfer(receiver, takingAmount - fee);
                }
            }
        }

        super._postInteraction(order, extension, orderHash, taker, makingAmount, takingAmount, remainingMakingAmount, extraData);
    }

    /**
     * @notice Retrieves funds accidently sent directly to the contract address
     * @param token ERC20 token to retrieve
     * @param amount amount to retrieve
     */
    function rescueFunds(IERC20 token, uint256 amount) external onlyOwner {
        token.uniTransfer(payable(msg.sender), amount);
    }

    function _sendEth(address target, uint256 amount) private {
        (bool success, ) = target.call{value: amount}("");
        if (!success) {
            revert EthTransferFailed();
        }
    }
}

File 26 of 32 : ResolverFeeExtension.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.23;

import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IOrderMixin } from "@1inch/limit-order-protocol-contract/contracts/interfaces/IOrderMixin.sol";
import { FeeBankCharger } from "../FeeBankCharger.sol";
import { BaseExtension } from "./BaseExtension.sol";
import { ExtensionLib } from "./ExtensionLib.sol";

/**
 * @title Resolver Fee Extension
 * @notice Abstract contract used as an extension in settlement contract to charge a fee resolver in the `postInteraction` method.
 */
abstract contract ResolverFeeExtension is BaseExtension, FeeBankCharger {
    using ExtensionLib for bytes;

    uint256 private constant _ORDER_FEE_BASE_POINTS = 1e15;

    constructor(IERC20 feeToken, address owner) FeeBankCharger(feeToken, owner) {}

    /**
     * @dev Calculates the resolver fee.
     * @param fee Scaled resolver fee.
     * @param orderMakingAmount Making amount from the order.
     * @param actualMakingAmount Making amount that was actually filled.
     * @return resolverFee Calculated resolver fee.
     */
    function _getResolverFee(
        uint256 fee,
        uint256 orderMakingAmount,
        uint256 actualMakingAmount
    ) internal pure virtual returns(uint256) {
        return fee * _ORDER_FEE_BASE_POINTS * actualMakingAmount / orderMakingAmount;
    }

    /**
     * @param extraData Structured data of length n bytes, segmented as follows:
     * [0:4] - Resolver fee information.
     * [4:n] - ExtraData for other extensions, not utilized by this resolver fee extension.
     * [n] - Bitmap indicating usage flags, where `xxxx xxx1` signifies resolver fee usage. Other bits in this bitmap are not used by this extension.
     */
    function _postInteraction(
        IOrderMixin.Order calldata order,
        bytes calldata extension,
        bytes32 orderHash,
        address taker,
        uint256 makingAmount,
        uint256 takingAmount,
        uint256 remainingMakingAmount,
        bytes calldata extraData
    ) internal virtual override {
        if (extraData.resolverFeeEnabled()) {
            uint256 resolverFee = _getResolverFee(uint256(uint32(bytes4(extraData[:4]))), order.makingAmount, makingAmount);
            _chargeFee(taker, resolverFee);
            extraData = extraData[4:];
        }
        super._postInteraction(order, extension, orderHash, taker, makingAmount, takingAmount, remainingMakingAmount, extraData);
    }
}

File 27 of 32 : WhitelistExtension.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.23;

import { IOrderMixin } from "@1inch/limit-order-protocol-contract/contracts/interfaces/IOrderMixin.sol";
import { BaseExtension } from "./BaseExtension.sol";
import { ExtensionLib } from "./ExtensionLib.sol";

/**
 * @title Whitelist Extension
 * @notice Abstract contract designed to check resolvers from orders in whitelist within the post-interaction phase of order execution.
 * Ensures that only transactions from whitelisted resolvers are processed, enhancing security and compliance.
 */
abstract contract WhitelistExtension is BaseExtension {
    using ExtensionLib for bytes;

    error ResolverIsNotWhitelisted();

    /**
     * @dev Validates whether the resolver is whitelisted.
     * @param whitelist Whitelist is tightly packed struct of the following format:
     * ```
     * struct WhitelistDetails {
     *     bytes4 auctionStartTime;
     *     (bytes10,bytes2)[N] resolversAddressesAndTimeDeltas;
     * }
     * ```
     * Resolvers in the list are sorted in ascending order by the time when they are allowed to interact with the order.
     * Time deltas represent the time in seconds between the adjacent resolvers.
     * Only 10 lowest bytes of the resolver address are used for comparison.
     * @param whitelistSize The amount of resolvers in the whitelist.
     * @param resolver The resolver to check.
     * @return Whether the resolver is whitelisted.
     */
    function _isWhitelisted(bytes calldata whitelist, uint256 whitelistSize, address resolver) internal view virtual returns (bool) {
        unchecked {
            uint256 allowedTime = uint32(bytes4(whitelist[0:4])); // initially set to auction start time
            whitelist = whitelist[4:];
            uint80 maskedResolverAddress = uint80(uint160(resolver));
            for (uint256 i = 0; i < whitelistSize; i++) {
                uint80 whitelistedAddress = uint80(bytes10(whitelist[:10]));
                allowedTime += uint16(bytes2(whitelist[10:12])); // add next time delta
                if (maskedResolverAddress == whitelistedAddress) {
                    return allowedTime <= block.timestamp;
                } else if (allowedTime > block.timestamp) {
                    return false;
                }
                whitelist = whitelist[12:];
            }
            return false;
        }
    }

    /**
     * @param extraData Structured data of length n bytes, segmented as follows:
     * [0:k] - Data as defined by the `whitelist` parameter for the `_isWhitelisted` method,
     *         where k depends on the amount of resolvers in the whitelist, as indicated by the bitmap in the last byte.
     * [k:n] - ExtraData for other extensions, not utilized by this whitelist extension.
     * [n]   - Bitmap `VVVV Vxxx` where V bits represent the amount of resolvers in the whitelist. The remaining bits in this bitmap are not used by this extension.
     */
    function _postInteraction(
        IOrderMixin.Order calldata order,
        bytes calldata extension,
        bytes32 orderHash,
        address taker,
        uint256 makingAmount,
        uint256 takingAmount,
        uint256 remainingMakingAmount,
        bytes calldata extraData
    ) internal virtual override {
        uint256 resolversCount = extraData.resolversCount();
        unchecked {
            uint256 whitelistSize = 4 + resolversCount * 12;
            if (!_isWhitelisted(extraData[:whitelistSize], resolversCount, taker)) revert ResolverIsNotWhitelisted();
            super._postInteraction(order, extension, orderHash, taker, makingAmount, takingAmount, remainingMakingAmount, extraData[whitelistSize:]);
        }
    }
}

File 28 of 32 : FeeBank.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.23;

import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { SafeERC20 } from "@1inch/solidity-utils/contracts/libraries/SafeERC20.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { IFeeBankCharger } from "./interfaces/IFeeBankCharger.sol";
import { IFeeBank } from "./interfaces/IFeeBank.sol";

/**
 * @title FeeBank
 * @notice FeeBank contract introduces a credit system for paying fees.
 * A user can deposit tokens to the FeeBank contract, obtain credits and then use them to pay fees.
 * @dev FeeBank is coupled with FeeBankCharger to actually charge fees.
 */
contract FeeBank is IFeeBank, Ownable {
    using SafeERC20 for IERC20;

    error ZeroAddress();

    IERC20 private immutable _FEE_TOKEN;
    IFeeBankCharger private immutable _CHARGER;

    mapping(address account => uint256 availableCredit) private _accountDeposits;

    constructor(IFeeBankCharger charger, IERC20 feeToken, address owner) Ownable(owner) {
        if (address(feeToken) == address(0)) revert ZeroAddress();
        _CHARGER = charger;
        _FEE_TOKEN = feeToken;
    }

    /**
     * @notice See {IFeeBank-availableCredit}.
     */
    function availableCredit(address account) external view returns (uint256) {
        return _CHARGER.availableCredit(account);
    }

    /**
     * @notice See {IFeeBank-deposit}.
     */
    function deposit(uint256 amount) external returns (uint256) {
        return _depositFor(msg.sender, amount);
    }

    /**
     * @notice See {IFeeBank-depositFor}.
     */
    function depositFor(address account, uint256 amount) external returns (uint256) {
        return _depositFor(account, amount);
    }

    /**
     * @notice See {IFeeBank-depositWithPermit}.
     */
    function depositWithPermit(uint256 amount, bytes calldata permit) external returns (uint256) {
        return depositForWithPermit(msg.sender, amount, permit);
    }

    /**
     * @notice See {IFeeBank-depositForWithPermit}.
     */
    function depositForWithPermit(
        address account,
        uint256 amount,
        bytes calldata permit
    ) public returns (uint256) {
        _FEE_TOKEN.safePermit(permit);
        return _depositFor(account, amount);
    }

    /**
     * @notice See {IFeeBank-withdraw}.
     */
    function withdraw(uint256 amount) external returns (uint256) {
        return _withdrawTo(msg.sender, amount);
    }

    /**
     * @notice See {IFeeBank-withdrawTo}.
     */
    function withdrawTo(address account, uint256 amount) external returns (uint256) {
        return _withdrawTo(account, amount);
    }

    /**
     * @notice Admin method returns commissions spent by users.
     * @param accounts Accounts whose commissions are being withdrawn.
     * @return totalAccountFees The total amount of accounts commissions.
     */
    function gatherFees(address[] calldata accounts) external onlyOwner returns (uint256 totalAccountFees) {
        uint256 accountsLength = accounts.length;
        unchecked {
            for (uint256 i = 0; i < accountsLength; ++i) {
                address account = accounts[i];
                uint256 accountDeposit = _accountDeposits[account];
                uint256 availableCredit_ = _CHARGER.availableCredit(account);
                _accountDeposits[account] = availableCredit_;
                totalAccountFees += accountDeposit - availableCredit_;  // overflow is impossible due to checks in FeeBankCharger
            }
        }
        _FEE_TOKEN.safeTransfer(msg.sender, totalAccountFees);
    }

    function _depositFor(address account, uint256 amount) internal returns (uint256 totalAvailableCredit) {
        if (account == address(0)) revert ZeroAddress();
        _FEE_TOKEN.safeTransferFrom(msg.sender, address(this), amount);
        unchecked {
            _accountDeposits[account] += amount;  // overflow is impossible due to limited _FEE_TOKEN supply
        }
        totalAvailableCredit = _CHARGER.increaseAvailableCredit(account, amount);
    }

    function _withdrawTo(address account, uint256 amount) internal returns (uint256 totalAvailableCredit) {
        totalAvailableCredit = _CHARGER.decreaseAvailableCredit(msg.sender, amount);
        unchecked {
            _accountDeposits[msg.sender] -= amount;  // underflow is impossible due to checks in FeeBankCharger
        }
        _FEE_TOKEN.safeTransfer(account, amount);
    }
}

File 29 of 32 : FeeBankCharger.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.23;

import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IFeeBank } from "./interfaces/IFeeBank.sol";
import { IFeeBankCharger } from "./interfaces/IFeeBankCharger.sol";
import { FeeBank } from "./FeeBank.sol";

/**
 * @title FeeBankCharger
 * @notice FeeBankCharger contract implements logic to increase or decrease users' credits in FeeBank.
 */
contract FeeBankCharger is IFeeBankCharger {
    error OnlyFeeBankAccess();
    error NotEnoughCredit();

    /**
     * @notice See {IFeeBankCharger-feeBank}.
     */
    IFeeBank public immutable FEE_BANK;
    mapping(address => uint256) private _creditAllowance;

    /**
     * @dev Modifier to check if the sender is a FEE_BANK contract.
     */
    modifier onlyFeeBank() {
        if (msg.sender != address(FEE_BANK)) revert OnlyFeeBankAccess();
        _;
    }

    constructor(IERC20 feeToken, address owner) {
        FEE_BANK = new FeeBank(this, feeToken, owner);
    }

    /**
     * @notice See {IFeeBankCharger-availableCredit}.
     */
    function availableCredit(address account) external view returns (uint256) {
        return _creditAllowance[account];
    }

    /**
     * @notice See {IFeeBankCharger-increaseAvailableCredit}.
     */
    function increaseAvailableCredit(address account, uint256 amount) external onlyFeeBank returns (uint256 allowance) {
        allowance = _creditAllowance[account];
        unchecked {
            allowance += amount;  // overflow is impossible due to limited _token supply
        }
        _creditAllowance[account] = allowance;
    }

    /**
     * @notice See {IFeeBankCharger-decreaseAvailableCredit}.
     */
    function decreaseAvailableCredit(address account, uint256 amount) external onlyFeeBank returns (uint256 allowance) {
        return _creditAllowance[account] -= amount;  // checked math is needed to prevent underflow
    }

    /**
     * @notice Internal function that charges a specified fee from a given account's credit allowance.
     * @dev Reverts with 'NotEnoughCredit' if the account's credit allowance is insufficient to cover the fee.
     * @param account The address of the account from which the fee is being charged.
     * @param fee The amount of fee to be charged from the account.
     */
    function _chargeFee(address account, uint256 fee) internal virtual {
        if (fee > 0) {
            uint256 currentAllowance = _creditAllowance[account];
            if (currentAllowance < fee) revert NotEnoughCredit();
            unchecked {
                _creditAllowance[account] = currentAllowance - fee;
            }
        }
    }
}

File 30 of 32 : IFeeBank.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IFeeBank {
    /**
     * @notice Returns the available credit for a given account in the FeeBank contract.
     * @param account The address of the account for which the available credit is being queried.
     * @return availableCredit The available credit of the queried account.
     */
    function availableCredit(address account) external view returns (uint256 availableCredit);

    /**
     * @notice Increases the caller's available credit by the specified amount.
     * @param amount The amount of credit to be added to the caller's account.
     * @return totalAvailableCredit The updated available credit of the caller's account.
     */
    function deposit(uint256 amount) external returns (uint256 totalAvailableCredit);

    /**
     * @notice Increases the specified account's available credit by the specified amount.
     * @param account The address of the account for which the available credit is being increased.
     * @param amount The amount of credit to be added to the account.
     * @return totalAvailableCredit The updated available credit of the specified account.
     */
    function depositFor(address account, uint256 amount) external returns (uint256 totalAvailableCredit);

    /**
     * @notice Increases the caller's available credit by a specified amount with permit.
     * @param amount The amount of credit to be added to the caller's account.
     * @param permit The permit data authorizing the transaction.
     * @return totalAvailableCredit The updated available credit of the caller's account.
     */
    function depositWithPermit(uint256 amount, bytes calldata permit) external returns (uint256 totalAvailableCredit);

    /**
     * @notice Increases the specified account's available credit by a specified amount with permit.
     * @param account The address of the account for which the available credit is being increased.
     * @param amount The amount of credit to be added to the account.
     * @param permit The permit data authorizing the transaction.
     * @return totalAvailableCredit The updated available credit of the specified account.
     */
    function depositForWithPermit(address account, uint256 amount, bytes calldata permit) external returns (uint256 totalAvailableCredit);

    /**
     * @notice Withdraws a specified amount of credit from the caller's account.
     * @param amount The amount of credit to be withdrawn from the caller's account.
     * @return totalAvailableCredit The updated available credit of the caller's account.
     */
    function withdraw(uint256 amount) external returns (uint256 totalAvailableCredit);

    /**
     * @notice Withdraws a specified amount of credit to the specified account.
     * @param account The address of the account to which the credit is being withdrawn.
     * @param amount The amount of credit to be withdrawn.
     * @return totalAvailableCredit The updated available credit of the caller's account.
     */
    function withdrawTo(address account, uint256 amount) external returns (uint256 totalAvailableCredit);
}

File 31 of 32 : IFeeBankCharger.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

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

interface IFeeBankCharger {
    /**
     * @notice Returns the instance of the FeeBank contract.
     * @return The instance of the FeeBank contract.
     */
    function FEE_BANK() external view returns (IFeeBank); // solhint-disable-line func-name-mixedcase

    /**
     * @notice Returns the available credit for a given account.
     * @param account The address of the account for which the available credit is being queried.
     * @return The available credit of the queried account.
     */
    function availableCredit(address account) external view returns (uint256);

    /**
     * @notice Increases the available credit of a given account by a specified amount.
     * @param account The address of the account for which the available credit is being increased.
     * @param amount The amount by which the available credit will be increased.
     * @return allowance The updated available credit of the specified account.
     */
    function increaseAvailableCredit(address account, uint256 amount) external returns (uint256 allowance);

    /**
     * @notice Decreases the available credit of a given account by a specified amount.
     * @param account The address of the account for which the available credit is being decreased.
     * @param amount The amount by which the available credit will be decreased.
     * @return allowance The updated available credit of the specified account.
     */
    function decreaseAvailableCredit(address account, uint256 amount) external returns (uint256 allowance);
}

File 32 of 32 : SimpleSettlement.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.23;

import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { IOrderMixin } from "@1inch/limit-order-protocol-contract/contracts/interfaces/IOrderMixin.sol";
import { BaseExtension } from "./extensions/BaseExtension.sol";
import { IntegratorFeeExtension } from "./extensions/IntegratorFeeExtension.sol";
import { ResolverFeeExtension } from "./extensions/ResolverFeeExtension.sol";
import { WhitelistExtension } from "./extensions/WhitelistExtension.sol";

/**
 * @title Simple Settlement contract
 * @notice Contract to execute limit orders settlement, created by Fusion mode.
 */
contract SimpleSettlement is WhitelistExtension, ResolverFeeExtension, IntegratorFeeExtension {
    /**
     * @notice Initializes the contract.
     * @param limitOrderProtocol The limit order protocol contract.
     * @param feeToken The token to charge protocol fees in.
     * @param weth The WETH address.
     * @param owner The owner of the contract.
     */
    constructor(address limitOrderProtocol, IERC20 feeToken, address weth, address owner)
        BaseExtension(limitOrderProtocol)
        ResolverFeeExtension(feeToken, owner)
        IntegratorFeeExtension(weth)
        Ownable(owner)
    {}

    function _postInteraction(
        IOrderMixin.Order calldata order,
        bytes calldata extension,
        bytes32 orderHash,
        address taker,
        uint256 makingAmount,
        uint256 takingAmount,
        uint256 remainingMakingAmount,
        bytes calldata extraData
    ) internal virtual override(WhitelistExtension, ResolverFeeExtension, IntegratorFeeExtension) {
        super._postInteraction(order, extension, orderHash, taker, makingAmount, takingAmount, remainingMakingAmount, extraData);
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 1000000
  },
  "evmVersion": "shanghai",
  "viaIR": true,
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "metadata": {
    "useLiteralContent": true
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"limitOrderProtocol","type":"address"},{"internalType":"contract IERC20","name":"feeToken","type":"address"},{"internalType":"address","name":"weth","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ETHTransferFailed","type":"error"},{"inputs":[],"name":"EthTransferFailed","type":"error"},{"inputs":[],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"InvalidPriorityFee","type":"error"},{"inputs":[],"name":"MathOverflowedMulDiv","type":"error"},{"inputs":[],"name":"NotEnoughCredit","type":"error"},{"inputs":[],"name":"OnlyFeeBankAccess","type":"error"},{"inputs":[],"name":"OnlyLimitOrderProtocol","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ResolverIsNotWhitelisted","type":"error"},{"inputs":[],"name":"SafeTransferFailed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"FEE_BANK","outputs":[{"internalType":"contract IFeeBank","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"availableCredit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"decreaseAvailableCredit","outputs":[{"internalType":"uint256","name":"allowance","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"Address","name":"maker","type":"uint256"},{"internalType":"Address","name":"receiver","type":"uint256"},{"internalType":"Address","name":"makerAsset","type":"uint256"},{"internalType":"Address","name":"takerAsset","type":"uint256"},{"internalType":"uint256","name":"makingAmount","type":"uint256"},{"internalType":"uint256","name":"takingAmount","type":"uint256"},{"internalType":"MakerTraits","name":"makerTraits","type":"uint256"}],"internalType":"struct IOrderMixin.Order","name":"order","type":"tuple"},{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"takingAmount","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"name":"getMakingAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"Address","name":"maker","type":"uint256"},{"internalType":"Address","name":"receiver","type":"uint256"},{"internalType":"Address","name":"makerAsset","type":"uint256"},{"internalType":"Address","name":"takerAsset","type":"uint256"},{"internalType":"uint256","name":"makingAmount","type":"uint256"},{"internalType":"uint256","name":"takingAmount","type":"uint256"},{"internalType":"MakerTraits","name":"makerTraits","type":"uint256"}],"internalType":"struct IOrderMixin.Order","name":"order","type":"tuple"},{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"makingAmount","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"name":"getTakingAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"increaseAvailableCredit","outputs":[{"internalType":"uint256","name":"allowance","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"Address","name":"maker","type":"uint256"},{"internalType":"Address","name":"receiver","type":"uint256"},{"internalType":"Address","name":"makerAsset","type":"uint256"},{"internalType":"Address","name":"takerAsset","type":"uint256"},{"internalType":"uint256","name":"makingAmount","type":"uint256"},{"internalType":"uint256","name":"takingAmount","type":"uint256"},{"internalType":"MakerTraits","name":"makerTraits","type":"uint256"}],"internalType":"struct IOrderMixin.Order","name":"order","type":"tuple"},{"internalType":"bytes","name":"extension","type":"bytes"},{"internalType":"bytes32","name":"orderHash","type":"bytes32"},{"internalType":"address","name":"taker","type":"address"},{"internalType":"uint256","name":"makingAmount","type":"uint256"},{"internalType":"uint256","name":"takingAmount","type":"uint256"},{"internalType":"uint256","name":"remainingMakingAmount","type":"uint256"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"name":"postInteraction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"Address","name":"maker","type":"uint256"},{"internalType":"Address","name":"receiver","type":"uint256"},{"internalType":"Address","name":"makerAsset","type":"uint256"},{"internalType":"Address","name":"takerAsset","type":"uint256"},{"internalType":"uint256","name":"makingAmount","type":"uint256"},{"internalType":"uint256","name":"takingAmount","type":"uint256"},{"internalType":"MakerTraits","name":"makerTraits","type":"uint256"}],"internalType":"struct IOrderMixin.Order","name":"order","type":"tuple"},{"internalType":"bytes","name":"extension","type":"bytes"},{"internalType":"bytes32","name":"orderHash","type":"bytes32"},{"internalType":"address","name":"taker","type":"address"},{"internalType":"uint256","name":"makingAmount","type":"uint256"},{"internalType":"uint256","name":"takingAmount","type":"uint256"},{"internalType":"uint256","name":"remainingMakingAmount","type":"uint256"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"name":"preInteraction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"rescueFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60e0346200018657601f6200283038819003918201601f1916830192916001600160401b03918285118486101762000172578160809285926040978852833981010312620001865762000052826200018a565b60208301516001600160a01b03918282169182900362000186576200008760606200007f8888016200018a565b96016200018a565b906080528551916110898084019584871090871117620001725760609284928692620017a785393088526020880152169485888201520301905ff080156200016857811660a05281156200015157600180546001600160a01b031981168417909155935193167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a360c0526116079081620001a082396080518181816106590152610e02015260a05181818161037901528181610c610152610d16015260c05181610a0e0152f35b8351631e4fbdf760e01b81525f6004820152602490fd5b84513d5f823e3d90fd5b634e487b7160e01b5f52604160045260245ffd5b5f80fd5b51906001600160a01b0382168203620001865756fe608060409080825260049081361015610022575b5050503615610020575f80fd5b005b5f3560e01c9081630986bdd514610dd1575080631d9671c314610d3a5780632ce26aeb14610ccc5780633ee5ef1f14610c10578063462ebde2146106265780635886216f146105c5578063715018a61461052957806378e3214f1461041957806385eda2de146103295780638da5cb5b146102d7578063d7ff8a80146101985763f2fde38b146100b25780610013565b346101945760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610194576100e9610e7d565b906100f26111fd565b73ffffffffffffffffffffffffffffffffffffffff809216928315610165575050600154827fffffffffffffffffffffffff0000000000000000000000000000000000000000821617600155167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3005b905f60249251917f1e4fbdf7000000000000000000000000000000000000000000000000000000008352820152fd5b5f80fd5b509034610194576101ba906101ac36610f4d565b95509350509693505061106a565b9060c08101359362989680928301908184116102ab5760a0916101dc91610ff3565b91013582810292818404149015171561027f576101fa828286611131565b9382156102535709610211575b6020925051908152f35b9060018101809111610227576020925090610207565b6011837f4e487b71000000000000000000000000000000000000000000000000000000005f525260245ffd5b6012867f4e487b71000000000000000000000000000000000000000000000000000000005f525260245ffd5b6011857f4e487b71000000000000000000000000000000000000000000000000000000005f525260245ffd5b6011877f4e487b71000000000000000000000000000000000000000000000000000000005f525260245ffd5b8234610194575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101945760209073ffffffffffffffffffffffffffffffffffffffff600154169051908152f35b503461019457817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019457610360610e7d565b73ffffffffffffffffffffffffffffffffffffffff90817f00000000000000000000000000000000000000000000000000000000000000001633036103f157165f525f602052815f209182549160243583039283116103c55750816020935551908152f35b6011907f4e487b71000000000000000000000000000000000000000000000000000000005f525260245ffd5b8284517fa4544199000000000000000000000000000000000000000000000000000000008152fd5b50903461019457807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019457813573ffffffffffffffffffffffffffffffffffffffff81169081810361019457602435916104766111fd565b8261047d57005b801590811561050b575b50156104fc57508047106104d5575f8080809333611388f16104a761124e565b50156104af57005b517fb12d13eb000000000000000000000000000000000000000000000000000000008152fd5b50517ff4d678b8000000000000000000000000000000000000000000000000000000008152fd5b909150610020925033906113e6565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee9150145f610487565b34610194575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101945761055f6111fd565b5f73ffffffffffffffffffffffffffffffffffffffff6001547fffffffffffffffffffffffff00000000000000000000000000000000000000008116600155167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b82346101945760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101945760209073ffffffffffffffffffffffffffffffffffffffff610615610e7d565b165f525f8252805f20549051908152f35b5090346101945761063636610ea0565b9398965093965050925073ffffffffffffffffffffffffffffffffffffffff90817f0000000000000000000000000000000000000000000000000000000000000000163303610be8576106876113a4565b15610bc057809280917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff95868201828111610b94576106eb907f0200000000000000000000000000000000000000000000000000000000000000918291858761147e565b351614610910575b505050829481978585018581116108e457610733907f0100000000000000000000000000000000000000000000000000000000000000918291888761147e565b3516146107c8575b5050505050810181811161079c5761075490828561147e565b3560fb1c90600c820286019081116101945761076f936114f9565b1561077657005b517f4b576069000000000000000000000000000000000000000000000000000000008152fd5b6011867f4e487b71000000000000000000000000000000000000000000000000000000005f525260245ffd5b91939750919394508689116101945766038d7ea4c68000833560e01c818102939181159185041417156108b8579161080a61080f9260a08c9695013592610ff3565b611033565b9283610848575b507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc9250019301905f8080808061073b565b851692835f525f602052875f2054818110610890577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc945f525f60205203875f20555f610816565b8389517fa7fd3792000000000000000000000000000000000000000000000000000000008152fd5b60118a7f4e487b71000000000000000000000000000000000000000000000000000000005f525260245ffd5b60118c7f4e487b71000000000000000000000000000000000000000000000000000000005f525260245ffd5b9194509150620186a061095785357fffff0000000000000000000000000000000000000000000000000000000000008082169160028710610b7f575b505060f01c83610ff3565b04908260161161019457600285013560601c9160168601917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffea850194839580988860208d013516957fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe98401838111610b50576109f8907f0400000000000000000000000000000000000000000000000000000000000000918291868561147e565b351614610ac3575b505050508560808a013516867f000000000000000000000000000000000000000000000000000000000000000016811480610a95575b15610a685750610a50938280610a58575b505003906114b7565b5f80806106f3565b610a61916114b7565b5f82610a47565b929190610a7f948280610a84575b505003916113e6565b610a50565b610a8e91866113e6565b5f82610a76565b507e8000000000000000000000000000000000000000000000000000000000000060e08b0135161515610a36565b9297509298509350357fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008082169160148610610b38575b505060601c9260141161019457602a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd691019401955f808080610a00565b908092506016886014030160031b1b16165f80610afa565b50505060118f7f4e487b71000000000000000000000000000000000000000000000000000000005f525260245ffd5b908092508660020360031b1b16165f8061094c565b60118d7f4e487b71000000000000000000000000000000000000000000000000000000005f525260245ffd5b8888517f8c331638000000000000000000000000000000000000000000000000000000008152fd5b8888517fd25aa106000000000000000000000000000000000000000000000000000000008152fd5b50903461019457807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019457610c48610e7d565b73ffffffffffffffffffffffffffffffffffffffff90817f0000000000000000000000000000000000000000000000000000000000000000163303610ca45760209350165f525f8252805f209060243582540180925551908152f35b5050517fa4544199000000000000000000000000000000000000000000000000000000008152fd5b8234610194575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610194576020905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b50903461019457610d5e91610d4e36610f4d565b955093505095949793505061106a565b90629896809182840293808504841490151715610da55782018092116103c5575092610d9e9160a0610d9660209660c0850135610ff3565b920135611131565b9051908152f35b6011827f4e487b71000000000000000000000000000000000000000000000000000000005f525260245ffd5b90503461019457610de136610ea0565b5050505050505050505073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163303610e2a57005b7fd25aa106000000000000000000000000000000000000000000000000000000008152fd5b9181601f840112156101945782359167ffffffffffffffff8311610194576020838186019501011161019457565b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361019457565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc81016101e0811261019457610100136101945760049167ffffffffffffffff610104358181116101945783610ef891600401610e4f565b9390939261012435926101443573ffffffffffffffffffffffffffffffffffffffff811681036101945792610164359261018435926101a435926101c43591821161019457610f4991600401610e4f565b9091565b907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc82016101c0811261019457610100136101945760049167ffffffffffffffff90610104358281116101945781610fa791600401610e4f565b9390939261012435926101443573ffffffffffffffffffffffffffffffffffffffff811681036101945792610164359261018435926101a43591821161019457610f4991600401610e4f565b8181029291811591840414171561100657565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b811561103d570490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b908060031161019457813560e81c8160071161019457600383013560e01c9080158015611129575b156111125750505f915b81600b1161019457600781013560e01c82600e116101945782601111610194577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffef6111009301916011810191600b600e83013560e81c92013560e81c8101906112e3565b8181111561110c570390565b50505f90565b620f424091611122914802611033565b049161109c565b508115611092565b9091828202917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff848209938380861095039480860395146111ed57848311156111c357829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b60046040517f227bc153000000000000000000000000000000000000000000000000000000008152fd5b5050906111fa9250611033565b90565b73ffffffffffffffffffffffffffffffffffffffff60015416330361121e57565b60246040517f118cdaa7000000000000000000000000000000000000000000000000000000008152336004820152fd5b3d156112de5767ffffffffffffffff903d8281116112b15760405192601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168401908111848210176112b15760405282523d5f602084013e565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b606090565b90919392814211155f146112f8575050505090565b829394919242101561139b57849291925b61131f57506111fa935082039142900302611033565b9060039085821161019457823560e81c906005928784116101945784013560f01c8101948542111561137c575050907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb9193920194019384611309565b9250936111fa9650809550849193500393429003029142030201611033565b50505050505f90565b483a03640277cf2a0048105f146113c2576064604648029102111590565b64183cd7f1004811156113dc576064604148029102111590565b489060011b111590565b9160446020925f92604051917fa9059cbb0000000000000000000000000000000000000000000000000000000083526004830152602482015282855af1908161145c575b501561143257565b60046040517ffb7f5079000000000000000000000000000000000000000000000000000000008152fd5b90503d15611476575060015f5114601f3d11165b5f61142a565b3b1515611470565b9082101561148a570190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f80809381935af16114c761124e565b50156114cf57565b60046040517f6d963f88000000000000000000000000000000000000000000000000000000008152fd5b9291909283600411610194579069ffffffffffffffffffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6004843560e01c940195019316925f925b828410611554575050505050505f90565b600a9082821161019457600c918383116101945787013560f01c0195803560b01c86036115875750505050505042101590565b95929394954284116115c65701949360010192917ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff49190910190611543565b505050505050505f9056fea26469706673582212205430c44c5fe34972cb4f2595e568f20c54bb9b66c75864ec1431738b3954cd4364736f6c6343000817003360c03461013057601f61108938819003918201601f19168301916001600160401b03831184841017610134578084926060946040528339810103126101305780516001600160a01b03808216820361013057602083015192818416908185036101305760400151828116809103610130578015610118575f80546001600160a01b03198116831782556040519416907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a315610109575060a052608052604051610f40908161014982396080518181816102e00152818161073401528181610bf90152610c78015260a0518181816102ad0152818161053d01528181610b9b0152610d4e0152f35b63d92e233d60e01b8152600490fd5b604051631e4fbdf760e01b81525f6004820152602490fd5b5f80fd5b634e487b7160e01b5f52604160045260245ffdfe604060808152600480361015610013575f80fd5b5f3560e01c8063205c28781461069a5780632e1a7d4d1461065c5780632f4f21e21461061657806332d323a5146105ad5780635886216f146104b8578063715018a61461041e5780638da5cb5b146103cd57806397a2cb641461021a578063b6b55f25146101dc578063bfe91734146101785763f2fde38b14610094575f80fd5b346101745760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610174576100cb6106e0565b906100d4610e22565b73ffffffffffffffffffffffffffffffffffffffff8092169283156101455750505f54827fffffffffffffffffffffffff00000000000000000000000000000000000000008216175f55167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3005b905f60249251917f1e4fbdf7000000000000000000000000000000000000000000000000000000008352820152fd5b5f80fd5b50903461017457807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101745760243567ffffffffffffffff8111610174576020926101cd6101d59236908301610703565b913533610731565b9051908152f35b5090346101745760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610174576101d56020923533610c53565b503461017457602091827ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261017457813567ffffffffffffffff808211610174573660238301121561017457818401359081116101745760059360243683871b8501820111610174579490610290610e22565b5f955f9473ffffffffffffffffffffffffffffffffffffffff90817f000000000000000000000000000000000000000000000000000000000000000016945b86881061030a578a8a8a61030482337f0000000000000000000000000000000000000000000000000000000000000000610e72565b51908152f35b9091929394959698848a831b8401013590848216809203610174575f8281526001808e52908b9020548b517f5886216f000000000000000000000000000000000000000000000000000000008152808a0185905293918e858a818e5afa9283156103c3578f905f94610393575b600196505f5252818c5f205503019901969594939291906102cf565b935085813d83116103bc575b6103a98183610aee565b81010312610174578e6001955193610377565b503d61039f565b8d513d5f823e3d90fd5b8234610174575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101745760209073ffffffffffffffffffffffffffffffffffffffff5f54169051908152f35b34610174575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261017457610454610e22565b5f73ffffffffffffffffffffffffffffffffffffffff81547fffffffffffffffffffffffff000000000000000000000000000000000000000081168355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b503461017457602091827ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261017457826104f36106e0565b602473ffffffffffffffffffffffffffffffffffffffff9182855196879485937f5886216f00000000000000000000000000000000000000000000000000000000855216908301527f0000000000000000000000000000000000000000000000000000000000000000165afa9182156105a3575f92610574575b5051908152f35b9091508281813d831161059c575b61058c8183610aee565b810103126101745751905f61056d565b503d610582565b50513d5f823e3d90fd5b5090346101745760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610174576105e66106e0565b916044359267ffffffffffffffff84116101745761060c6101d592602095369101610703565b9160243590610731565b823461017457807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610174576020906101d56106536106e0565b60243590610c53565b5090346101745760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610174576101d56020923533610b5c565b823461017457807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610174576020906101d56106d76106e0565b60243590610b5c565b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361017457565b9181601f840112156101745782359167ffffffffffffffff8311610174576020838186019501011161017457565b917f0000000000000000000000000000000000000000000000000000000000000000604051949081606414610a34578160481461096e578160e0146109315781610100146108f257816060146108175750610160146107b2576004847f68275857000000000000000000000000000000000000000000000000000000008152fd5b610164846101605f949596937f2b67b570000000000000000000000000000000000000000000000000000000008695526004830137826e22d473030f116ddee9f6b43ac78ba35af15b1561080c5761080991610c53565b90565b6040513d5f823e3d90fd5b610164915094602060405f9596979486957f2b67b570000000000000000000000000000000000000000000000000000000008552336004860152602485015260148160508601377fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff65ffffffffffff9080601484013560e01c0182166064870152601883013560e01c60848701523060a4870152601c83013560e01c011660c485015261010060e4850152816101048501528280820161012486013701610144830137826e22d473030f116ddee9f6b43ac78ba35af16107fb565b6101049150945f8094959661010082957f8fcbaf0c00000000000000000000000000000000000000000000000000000000855260048501375af16107fb565b60e49150945f8094959660e082957fd505accf00000000000000000000000000000000000000000000000000000000855260048501375af16107fb565b6101049150945f809495967f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82957f8fcbaf0c00000000000000000000000000000000000000000000000000000000855233600486015230602486015260206008602883013592803560e01c60448901527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600482013560e01c016064890152600160848901528360ff1c601b0160a48901520160c48701371660e48401525af16107fb565b60e49150945f809495967f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82957fd505accf00000000000000000000000000000000000000000000000000000000855233600486015230602486015260206024604483013592828160448a01377fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8382013560e01c0160648901528360ff1c601b0160848901520160a48701371660c48401525af16107fb565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117610b2f57604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6040517f85eda2de000000000000000000000000000000000000000000000000000000008152336004820152602481018390529092916020826044815f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff165af1801561080c575f90610c1f575b610c1d925093335f52600160205260405f208281540390557f0000000000000000000000000000000000000000000000000000000000000000610e72565b565b506020823d602011610c4b575b81610c3960209383610aee565b8101031261017457610c1d9151610bdf565b3d9150610c2c565b73ffffffffffffffffffffffffffffffffffffffff91828216908115610df8576064937f00000000000000000000000000000000000000000000000000000000000000006040517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201528360448201525f602097889282855af19081610dd6575b5015610dac575f928352600185526040808420805484019055517f3ee5ef1f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff94909416600485015260248401919091528391839160449183917f0000000000000000000000000000000000000000000000000000000000000000165af191821561080c575f92610d8257505090565b90809250813d8311610da5575b610d998183610aee565b81010312610174575190565b503d610d8f565b60046040517ff4059071000000000000000000000000000000000000000000000000000000008152fd5b90503d15610df0575060015f5114601f3d11165b5f610ce0565b3b1515610dea565b60046040517fd92e233d000000000000000000000000000000000000000000000000000000008152fd5b73ffffffffffffffffffffffffffffffffffffffff5f54163303610e4257565b60246040517f118cdaa7000000000000000000000000000000000000000000000000000000008152336004820152fd5b9160446020925f92604051917fa9059cbb0000000000000000000000000000000000000000000000000000000083526004830152602482015282855af19081610ee8575b5015610ebe57565b60046040517ffb7f5079000000000000000000000000000000000000000000000000000000008152fd5b90503d15610f02575060015f5114601f3d11165b5f610eb6565b3b1515610efc56fea264697066735822122050c2fc8dc11068b5d74ada2d460fc0ef6ed99e8277f609a89ab6190cd71916b864736f6c63430008170033000000000000000000000000111111125421ca6dc452d289314280a0f8842a65000000000000000000000000111111111117dc0aa78b770fa6a738034120c302000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000011799622f4d98a24514011e8527b969f7488ef47

Deployed Bytecode

0x608060409080825260049081361015610022575b5050503615610020575f80fd5b005b5f3560e01c9081630986bdd514610dd1575080631d9671c314610d3a5780632ce26aeb14610ccc5780633ee5ef1f14610c10578063462ebde2146106265780635886216f146105c5578063715018a61461052957806378e3214f1461041957806385eda2de146103295780638da5cb5b146102d7578063d7ff8a80146101985763f2fde38b146100b25780610013565b346101945760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610194576100e9610e7d565b906100f26111fd565b73ffffffffffffffffffffffffffffffffffffffff809216928315610165575050600154827fffffffffffffffffffffffff0000000000000000000000000000000000000000821617600155167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3005b905f60249251917f1e4fbdf7000000000000000000000000000000000000000000000000000000008352820152fd5b5f80fd5b509034610194576101ba906101ac36610f4d565b95509350509693505061106a565b9060c08101359362989680928301908184116102ab5760a0916101dc91610ff3565b91013582810292818404149015171561027f576101fa828286611131565b9382156102535709610211575b6020925051908152f35b9060018101809111610227576020925090610207565b6011837f4e487b71000000000000000000000000000000000000000000000000000000005f525260245ffd5b6012867f4e487b71000000000000000000000000000000000000000000000000000000005f525260245ffd5b6011857f4e487b71000000000000000000000000000000000000000000000000000000005f525260245ffd5b6011877f4e487b71000000000000000000000000000000000000000000000000000000005f525260245ffd5b8234610194575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101945760209073ffffffffffffffffffffffffffffffffffffffff600154169051908152f35b503461019457817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019457610360610e7d565b73ffffffffffffffffffffffffffffffffffffffff90817f000000000000000000000000798ef9b5e2dd6cfddb1e6a3e09bb6e4531492db11633036103f157165f525f602052815f209182549160243583039283116103c55750816020935551908152f35b6011907f4e487b71000000000000000000000000000000000000000000000000000000005f525260245ffd5b8284517fa4544199000000000000000000000000000000000000000000000000000000008152fd5b50903461019457807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019457813573ffffffffffffffffffffffffffffffffffffffff81169081810361019457602435916104766111fd565b8261047d57005b801590811561050b575b50156104fc57508047106104d5575f8080809333611388f16104a761124e565b50156104af57005b517fb12d13eb000000000000000000000000000000000000000000000000000000008152fd5b50517ff4d678b8000000000000000000000000000000000000000000000000000000008152fd5b909150610020925033906113e6565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee9150145f610487565b34610194575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101945761055f6111fd565b5f73ffffffffffffffffffffffffffffffffffffffff6001547fffffffffffffffffffffffff00000000000000000000000000000000000000008116600155167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b82346101945760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101945760209073ffffffffffffffffffffffffffffffffffffffff610615610e7d565b165f525f8252805f20549051908152f35b5090346101945761063636610ea0565b9398965093965050925073ffffffffffffffffffffffffffffffffffffffff90817f000000000000000000000000111111125421ca6dc452d289314280a0f8842a65163303610be8576106876113a4565b15610bc057809280917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff95868201828111610b94576106eb907f0200000000000000000000000000000000000000000000000000000000000000918291858761147e565b351614610910575b505050829481978585018581116108e457610733907f0100000000000000000000000000000000000000000000000000000000000000918291888761147e565b3516146107c8575b5050505050810181811161079c5761075490828561147e565b3560fb1c90600c820286019081116101945761076f936114f9565b1561077657005b517f4b576069000000000000000000000000000000000000000000000000000000008152fd5b6011867f4e487b71000000000000000000000000000000000000000000000000000000005f525260245ffd5b91939750919394508689116101945766038d7ea4c68000833560e01c818102939181159185041417156108b8579161080a61080f9260a08c9695013592610ff3565b611033565b9283610848575b507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc9250019301905f8080808061073b565b851692835f525f602052875f2054818110610890577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc945f525f60205203875f20555f610816565b8389517fa7fd3792000000000000000000000000000000000000000000000000000000008152fd5b60118a7f4e487b71000000000000000000000000000000000000000000000000000000005f525260245ffd5b60118c7f4e487b71000000000000000000000000000000000000000000000000000000005f525260245ffd5b9194509150620186a061095785357fffff0000000000000000000000000000000000000000000000000000000000008082169160028710610b7f575b505060f01c83610ff3565b04908260161161019457600285013560601c9160168601917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffea850194839580988860208d013516957fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe98401838111610b50576109f8907f0400000000000000000000000000000000000000000000000000000000000000918291868561147e565b351614610ac3575b505050508560808a013516867f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216811480610a95575b15610a685750610a50938280610a58575b505003906114b7565b5f80806106f3565b610a61916114b7565b5f82610a47565b929190610a7f948280610a84575b505003916113e6565b610a50565b610a8e91866113e6565b5f82610a76565b507e8000000000000000000000000000000000000000000000000000000000000060e08b0135161515610a36565b9297509298509350357fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008082169160148610610b38575b505060601c9260141161019457602a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd691019401955f808080610a00565b908092506016886014030160031b1b16165f80610afa565b50505060118f7f4e487b71000000000000000000000000000000000000000000000000000000005f525260245ffd5b908092508660020360031b1b16165f8061094c565b60118d7f4e487b71000000000000000000000000000000000000000000000000000000005f525260245ffd5b8888517f8c331638000000000000000000000000000000000000000000000000000000008152fd5b8888517fd25aa106000000000000000000000000000000000000000000000000000000008152fd5b50903461019457807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019457610c48610e7d565b73ffffffffffffffffffffffffffffffffffffffff90817f000000000000000000000000798ef9b5e2dd6cfddb1e6a3e09bb6e4531492db1163303610ca45760209350165f525f8252805f209060243582540180925551908152f35b5050517fa4544199000000000000000000000000000000000000000000000000000000008152fd5b8234610194575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610194576020905173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000798ef9b5e2dd6cfddb1e6a3e09bb6e4531492db1168152f35b50903461019457610d5e91610d4e36610f4d565b955093505095949793505061106a565b90629896809182840293808504841490151715610da55782018092116103c5575092610d9e9160a0610d9660209660c0850135610ff3565b920135611131565b9051908152f35b6011827f4e487b71000000000000000000000000000000000000000000000000000000005f525260245ffd5b90503461019457610de136610ea0565b5050505050505050505073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000111111125421ca6dc452d289314280a0f8842a65163303610e2a57005b7fd25aa106000000000000000000000000000000000000000000000000000000008152fd5b9181601f840112156101945782359167ffffffffffffffff8311610194576020838186019501011161019457565b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361019457565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc81016101e0811261019457610100136101945760049167ffffffffffffffff610104358181116101945783610ef891600401610e4f565b9390939261012435926101443573ffffffffffffffffffffffffffffffffffffffff811681036101945792610164359261018435926101a435926101c43591821161019457610f4991600401610e4f565b9091565b907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc82016101c0811261019457610100136101945760049167ffffffffffffffff90610104358281116101945781610fa791600401610e4f565b9390939261012435926101443573ffffffffffffffffffffffffffffffffffffffff811681036101945792610164359261018435926101a43591821161019457610f4991600401610e4f565b8181029291811591840414171561100657565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b811561103d570490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b908060031161019457813560e81c8160071161019457600383013560e01c9080158015611129575b156111125750505f915b81600b1161019457600781013560e01c82600e116101945782601111610194577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffef6111009301916011810191600b600e83013560e81c92013560e81c8101906112e3565b8181111561110c570390565b50505f90565b620f424091611122914802611033565b049161109c565b508115611092565b9091828202917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff848209938380861095039480860395146111ed57848311156111c357829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b60046040517f227bc153000000000000000000000000000000000000000000000000000000008152fd5b5050906111fa9250611033565b90565b73ffffffffffffffffffffffffffffffffffffffff60015416330361121e57565b60246040517f118cdaa7000000000000000000000000000000000000000000000000000000008152336004820152fd5b3d156112de5767ffffffffffffffff903d8281116112b15760405192601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168401908111848210176112b15760405282523d5f602084013e565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b606090565b90919392814211155f146112f8575050505090565b829394919242101561139b57849291925b61131f57506111fa935082039142900302611033565b9060039085821161019457823560e81c906005928784116101945784013560f01c8101948542111561137c575050907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb9193920194019384611309565b9250936111fa9650809550849193500393429003029142030201611033565b50505050505f90565b483a03640277cf2a0048105f146113c2576064604648029102111590565b64183cd7f1004811156113dc576064604148029102111590565b489060011b111590565b9160446020925f92604051917fa9059cbb0000000000000000000000000000000000000000000000000000000083526004830152602482015282855af1908161145c575b501561143257565b60046040517ffb7f5079000000000000000000000000000000000000000000000000000000008152fd5b90503d15611476575060015f5114601f3d11165b5f61142a565b3b1515611470565b9082101561148a570190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f80809381935af16114c761124e565b50156114cf57565b60046040517f6d963f88000000000000000000000000000000000000000000000000000000008152fd5b9291909283600411610194579069ffffffffffffffffffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6004843560e01c940195019316925f925b828410611554575050505050505f90565b600a9082821161019457600c918383116101945787013560f01c0195803560b01c86036115875750505050505042101590565b95929394954284116115c65701949360010192917ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff49190910190611543565b505050505050505f9056fea26469706673582212205430c44c5fe34972cb4f2595e568f20c54bb9b66c75864ec1431738b3954cd4364736f6c63430008170033

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

000000000000000000000000111111125421ca6dc452d289314280a0f8842a65000000000000000000000000111111111117dc0aa78b770fa6a738034120c302000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000011799622f4d98a24514011e8527b969f7488ef47

-----Decoded View---------------
Arg [0] : limitOrderProtocol (address): 0x111111125421cA6dc452d289314280a0f8842A65
Arg [1] : feeToken (address): 0x111111111117dC0aa78b770fA6A738034120C302
Arg [2] : weth (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
Arg [3] : owner (address): 0x11799622F4D98A24514011E8527B969f7488eF47

-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 000000000000000000000000111111125421ca6dc452d289314280a0f8842a65
Arg [1] : 000000000000000000000000111111111117dc0aa78b770fa6a738034120c302
Arg [2] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Arg [3] : 00000000000000000000000011799622f4d98a24514011e8527b969f7488ef47


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  ]

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.