ETH Price: $3,285.72 (-1.34%)
Gas: 4.49 Gwei

Contract

0xA88800CD213dA5Ae406ce248380802BD53b47647
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

Transaction Hash
Method
Block
From
To
Settle Orders201420992024-06-21 19:11:35184 days ago1718997095IN
1inch: Settlement
0 ETH0.000808527.05264551
Settle Orders201420952024-06-21 19:10:47184 days ago1718997047IN
1inch: Settlement
0 ETH0.000247096.87578116
Settle Orders201420602024-06-21 19:03:47184 days ago1718996627IN
1inch: Settlement
0 ETH0.000929688.1104247
Settle Orders201419672024-06-21 18:44:59184 days ago1718995499IN
1inch: Settlement
0 ETH0.000490994.95907104
Settle Orders201419402024-06-21 18:39:35184 days ago1718995175IN
1inch: Settlement
0 ETH0.000582485.89170576
Settle Orders201418632024-06-21 18:23:59184 days ago1718994239IN
1inch: Settlement
0 ETH0.000645386.42157121
Settle Orders201417722024-06-21 18:04:59184 days ago1718993099IN
1inch: Settlement
0 ETH0.000184936.52731216
Settle Orders198827232024-05-16 13:05:35220 days ago1715864735IN
1inch: Settlement
0 ETH0.002576139.50754889
Settle Orders198826612024-05-16 12:52:59220 days ago1715863979IN
1inch: Settlement
0 ETH0.001442187.44576253
Settle Orders198826292024-05-16 12:46:35220 days ago1715863595IN
1inch: Settlement
0 ETH0.001407066.37105872
Settle Orders198825692024-05-16 12:34:35220 days ago1715862875IN
1inch: Settlement
0 ETH0.001899796.4139273
Settle Orders198824482024-05-16 12:10:23220 days ago1715861423IN
1inch: Settlement
0 ETH0.00199037.21375494
Settle Orders198823842024-05-16 11:57:23220 days ago1715860643IN
1inch: Settlement
0 ETH0.001219485.0410393
Settle Orders198823812024-05-16 11:56:47220 days ago1715860607IN
1inch: Settlement
0 ETH0.001293265.08907344
Settle Orders198819712024-05-16 10:34:23220 days ago1715855663IN
1inch: Settlement
0 ETH0.00244498.81233871
Settle Orders198818522024-05-16 10:10:35220 days ago1715854235IN
1inch: Settlement
0 ETH0.001421665.45186198
Settle Orders198814522024-05-16 8:50:11220 days ago1715849411IN
1inch: Settlement
0 ETH0.001284175.76977473
Settle Orders198813442024-05-16 8:28:35220 days ago1715848115IN
1inch: Settlement
0 ETH0.00141646.08969158
Settle Orders198812662024-05-16 8:12:47220 days ago1715847167IN
1inch: Settlement
0 ETH0.001458436.72750653
Settle Orders198805802024-05-16 5:54:23221 days ago1715838863IN
1inch: Settlement
0 ETH0.001118095.3159457
Settle Orders198803232024-05-16 5:02:35221 days ago1715835755IN
1inch: Settlement
0 ETH0.001143434.51213356
Settle Orders198799142024-05-16 3:39:47221 days ago1715830787IN
1inch: Settlement
0 ETH0.001740985.75409261
Settle Orders198792302024-05-16 1:22:35221 days ago1715822555IN
1inch: Settlement
0 ETH0.000976234.76578442
Settle Orders198787742024-05-15 23:50:35221 days ago1715817035IN
1inch: Settlement
0 ETH0.001540095.84527848
Settle Orders198779322024-05-15 21:00:59221 days ago1715806859IN
1inch: Settlement
0 ETH0.0026577311.76656812
View all transactions

Latest 3 internal transactions

Advanced mode:
Parent Transaction Hash Block
From
To
205993442024-08-24 15:26:47120 days ago1724513207
1inch: Settlement
0 ETH
199724072024-05-29 2:01:59208 days ago1716948119
1inch: Settlement
0 ETH
162412362022-12-22 15:47:59731 days ago1671724079
1inch: Settlement
 Contract Creation0 ETH
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Settlement

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 1000000 runs

Other Settings:
default evmVersion
File 1 of 24 : Settlement.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@1inch/limit-order-protocol-contract/contracts/interfaces/IOrderMixin.sol";
import "@1inch/solidity-utils/contracts/libraries/SafeERC20.sol";
import "./interfaces/ISettlement.sol";
import "./interfaces/IResolver.sol";
import "./libraries/DynamicSuffix.sol";
import "./libraries/OrderSaltParser.sol";
import "./libraries/OrderSuffix.sol";
import "./FeeBankCharger.sol";

contract Settlement is ISettlement, FeeBankCharger {
    using SafeERC20 for IERC20;
    using OrderSaltParser for uint256;
    using DynamicSuffix for bytes;
    using AddressLib for Address;
    using OrderSuffix for OrderLib.Order;
    using TakingFee for TakingFee.Data;

    error AccessDenied();
    error IncorrectCalldataParams();
    error FailedExternalCall();
    error ResolverIsNotWhitelisted();
    error WrongInteractionTarget();

    bytes1 private constant _FINALIZE_INTERACTION = 0x01;
    uint256 private constant _ORDER_FEE_BASE_POINTS = 1e15;
    uint256 private constant _BASE_POINTS = 10_000_000; // 100%

    IOrderMixin private immutable _limitOrderProtocol;

    modifier onlyThis(address account) {
        if (account != address(this)) revert AccessDenied();
        _;
    }

    modifier onlyLimitOrderProtocol {
        if (msg.sender != address(_limitOrderProtocol)) revert AccessDenied();
        _;
    }

    constructor(IOrderMixin limitOrderProtocol, IERC20 token)
        FeeBankCharger(token)
    {
        _limitOrderProtocol = limitOrderProtocol;
    }

    function settleOrders(bytes calldata data) external {
        _settleOrder(data, msg.sender, 0, new bytes(0));
    }

    function fillOrderInteraction(
        address taker,
        uint256, /* makingAmount */
        uint256 takingAmount,
        bytes calldata interactiveData
    ) external onlyThis(taker) onlyLimitOrderProtocol returns (uint256 result) {
        (DynamicSuffix.Data calldata suffix, bytes calldata tokensAndAmounts, bytes calldata interaction) = interactiveData.decodeSuffix();
        IERC20 token = IERC20(suffix.token.get());
        result = takingAmount * (_BASE_POINTS + suffix.rateBump) / _BASE_POINTS;
        uint256 takingFee = result * suffix.takingFee.ratio() / TakingFee._TAKING_FEE_BASE;

        bytes memory allTokensAndAmounts = new bytes(tokensAndAmounts.length + 0x40);
        assembly {
            let ptr := add(allTokensAndAmounts, 0x20)
            calldatacopy(ptr, tokensAndAmounts.offset, tokensAndAmounts.length)
            ptr := add(ptr, tokensAndAmounts.length)
            mstore(ptr, token)
            mstore(add(ptr, 0x20), add(result, takingFee))
        }

        if (interactiveData[0] == _FINALIZE_INTERACTION) {
            _chargeFee(suffix.resolver.get(), suffix.totalFee);
            address target = address(bytes20(interaction));
            bytes calldata data = interaction[20:];
            IResolver(target).resolveOrders(suffix.resolver.get(), allTokensAndAmounts, data);
        } else {
            _settleOrder(
                interaction,
                suffix.resolver.get(),
                suffix.totalFee,
                allTokensAndAmounts
            );
        }

        if (takingFee > 0) {
            token.safeTransfer(suffix.takingFee.receiver(), takingFee);
        }
        token.forceApprove(address(_limitOrderProtocol), result);
    }

    bytes4 private constant _FILL_ORDER_TO_SELECTOR = 0xe5d7bde6; // IOrderMixin.fillOrderTo.selector
    bytes4 private constant _WRONG_INTERACTION_TARGET_SELECTOR = 0x5b34bf89; // WrongInteractionTarget.selector

    function _settleOrder(bytes calldata data, address resolver, uint256 totalFee, bytes memory tokensAndAmounts) private {
        OrderLib.Order calldata order;
        assembly {
            order := add(data.offset, calldataload(data.offset))
        }
        if (!order.checkResolver(resolver)) revert ResolverIsNotWhitelisted();
        TakingFee.Data takingFeeData = order.takingFee();
        totalFee += order.salt.getFee() * _ORDER_FEE_BASE_POINTS;

        uint256 rateBump = order.rateBump();
        uint256 suffixLength = DynamicSuffix._STATIC_DATA_SIZE + tokensAndAmounts.length + 0x20;
        IOrderMixin limitOrderProtocol = _limitOrderProtocol;

        assembly {
            function memcpy(dst, src, len) {
                pop(staticcall(gas(), 0x4, src, len, dst, len))
            }

            let interactionLengthOffset := calldataload(add(data.offset, 0x40))
            let interactionOffset := add(interactionLengthOffset, 0x20)
            let interactionLength := calldataload(add(data.offset, interactionLengthOffset))

            { // stack too deep
                let target := shr(96, calldataload(add(data.offset, interactionOffset)))
                if or(lt(interactionLength, 20), iszero(eq(target, address()))) {
                    mstore(0, _WRONG_INTERACTION_TARGET_SELECTOR)
                    revert(0, 4)
                }
            }

            // Copy calldata and patch interaction.length
            let ptr := mload(0x40)
            mstore(ptr, _FILL_ORDER_TO_SELECTOR)
            calldatacopy(add(ptr, 4), data.offset, data.length)
            mstore(add(add(ptr, interactionLengthOffset), 4), add(interactionLength, suffixLength))

            {  // stack too deep
                // Append suffix fields
                let offset := add(add(ptr, interactionOffset), interactionLength)
                mstore(add(offset, 0x04), totalFee)
                mstore(add(offset, 0x24), resolver)
                mstore(add(offset, 0x44), calldataload(add(order, 0x40)))  // takerAsset
                mstore(add(offset, 0x64), rateBump)
                mstore(add(offset, 0x84), takingFeeData)
                let tokensAndAmountsLength := mload(tokensAndAmounts)
                memcpy(add(offset, 0xa4), add(tokensAndAmounts, 0x20), tokensAndAmountsLength)
                mstore(add(offset, add(0xa4, tokensAndAmountsLength)), tokensAndAmountsLength)
            }

            // Call fillOrderTo
            if iszero(call(gas(), limitOrderProtocol, 0, ptr, add(add(4, suffixLength), data.length), ptr, 0)) {
                returndatacopy(ptr, 0, returndatasize())
                revert(ptr, returndatasize())
            }
        }
    }
}

File 2 of 24 : IInteractionNotificationReceiver.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;
pragma abicoder v1;

/**
 * @title Interface for interactor which acts after `taker -> maker` transfers.
 * @notice The order filling steps are `preInteraction` =>` Transfer "maker -> taker"` => **`Interaction`** => `Transfer "taker -> maker"` => `postInteraction`
 */
interface IInteractionNotificationReceiver {
    /**
     * @notice Callback method that gets called after all funds transfers
     * @param taker Taker address (tx sender)
     * @param makingAmount Actual making amount
     * @param takingAmount Actual taking amount
     * @param interactionData Interaction calldata
     * @return offeredTakingAmount Suggested amount. Order is filled with this amount if maker or taker getter functions are not defined.
     */
    function fillOrderInteraction(
        address taker,
        uint256 makingAmount,
        uint256 takingAmount,
        bytes memory interactionData
    ) external returns(uint256 offeredTakingAmount);
}

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

pragma solidity 0.8.17;

import "../OrderLib.sol";

interface IOrderMixin {
    /**
     * @notice Returns unfilled amount for order. Throws if order does not exist
     * @param orderHash Order's hash. Can be obtained by the `hashOrder` function
     * @return amount Unfilled amount
     */
    function remaining(bytes32 orderHash) external view returns(uint256 amount);

    /**
     * @notice Returns unfilled amount for order
     * @param orderHash Order's hash. Can be obtained by the `hashOrder` function
     * @return rawAmount Unfilled amount of order plus one if order exists. Otherwise 0
     */
    function remainingRaw(bytes32 orderHash) external view returns(uint256 rawAmount);

    /**
     * @notice Same as `remainingRaw` but for multiple orders
     * @param orderHashes Array of hashes
     * @return rawAmounts Array of amounts for each order plus one if order exists or 0 otherwise
     */
    function remainingsRaw(bytes32[] memory orderHashes) external view returns(uint256[] memory rawAmounts);

    /**
     * @notice Checks order predicate
     * @param order Order to check predicate for
     * @return result Predicate evaluation result. True if predicate allows to fill the order, false otherwise
     */
    function checkPredicate(OrderLib.Order calldata order) external view returns(bool result);

    /**
     * @notice Returns order hash according to EIP712 standard
     * @param order Order to get hash for
     * @return orderHash Hash of the order
     */
    function hashOrder(OrderLib.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 Cancels order.
     * @dev Order is cancelled by setting remaining amount to _ORDER_FILLED value
     * @param order Order quote to cancel
     * @return orderRemaining Unfilled amount of order before cancellation
     * @return orderHash Hash of the filled order
     */
    function cancelOrder(OrderLib.Order calldata order) external returns(uint256 orderRemaining, bytes32 orderHash);

    /**
     * @notice Fills an order. If one doesn't exist (first fill) it will be created using order.makerAssetData
     * @param order Order quote to fill
     * @param signature Signature to confirm quote ownership
     * @param interaction A call data for InteractiveNotificationReceiver. Taker may execute interaction after getting maker assets and before sending taker assets.
     * @param makingAmount Making amount
     * @param takingAmount Taking amount
     * @param skipPermitAndThresholdAmount Specifies maximum allowed takingAmount when takingAmount is zero, otherwise specifies minimum allowed makingAmount. Top-most bit specifies whether taker wants to skip maker's permit.
     * @return actualMakingAmount Actual amount transferred from maker to taker
     * @return actualTakingAmount Actual amount transferred from taker to maker
     * @return orderHash Hash of the filled order
     */
    function fillOrder(
        OrderLib.Order calldata order,
        bytes calldata signature,
        bytes calldata interaction,
        uint256 makingAmount,
        uint256 takingAmount,
        uint256 skipPermitAndThresholdAmount
    ) external payable returns(uint256 actualMakingAmount, uint256 actualTakingAmount, bytes32 orderHash);

    /**
     * @notice Same as `fillOrderTo` but calls permit first,
     * allowing to approve token spending and make a swap in one transaction.
     * Also allows to specify funds destination instead of `msg.sender`
     * @dev See tests for examples
     * @param order Order quote to fill
     * @param signature Signature to confirm quote ownership
     * @param interaction A call data for InteractiveNotificationReceiver. Taker may execute interaction after getting maker assets and before sending taker assets.
     * @param makingAmount Making amount
     * @param takingAmount Taking amount
     * @param skipPermitAndThresholdAmount Specifies maximum allowed takingAmount when takingAmount is zero, otherwise specifies minimum allowed makingAmount. Top-most bit specifies whether taker wants to skip maker's permit.
     * @param target Address that will receive swap funds
     * @param permit Should consist of abiencoded token address and encoded `IERC20Permit.permit` call.
     * @return actualMakingAmount Actual amount transferred from maker to taker
     * @return actualTakingAmount Actual amount transferred from taker to maker
     * @return orderHash Hash of the filled order
     */
    function fillOrderToWithPermit(
        OrderLib.Order calldata order,
        bytes calldata signature,
        bytes calldata interaction,
        uint256 makingAmount,
        uint256 takingAmount,
        uint256 skipPermitAndThresholdAmount,
        address target,
        bytes calldata permit
    ) external returns(uint256 actualMakingAmount, uint256 actualTakingAmount, bytes32 orderHash);

    /**
     * @notice Same as `fillOrder` but allows to specify funds destination instead of `msg.sender`
     * @param order_ Order quote to fill
     * @param signature Signature to confirm quote ownership
     * @param interaction A call data for InteractiveNotificationReceiver. Taker may execute interaction after getting maker assets and before sending taker assets.
     * @param makingAmount Making amount
     * @param takingAmount Taking amount
     * @param skipPermitAndThresholdAmount Specifies maximum allowed takingAmount when takingAmount is zero, otherwise specifies minimum allowed makingAmount. Top-most bit specifies whether taker wants to skip maker's permit.
     * @param target Address that will receive swap funds
     * @return actualMakingAmount Actual amount transferred from maker to taker
     * @return actualTakingAmount Actual amount transferred from taker to maker
     * @return orderHash Hash of the filled order
     */
    function fillOrderTo(
        OrderLib.Order calldata order_,
        bytes calldata signature,
        bytes calldata interaction,
        uint256 makingAmount,
        uint256 takingAmount,
        uint256 skipPermitAndThresholdAmount,
        address target
    ) external payable returns(uint256 actualMakingAmount, uint256 actualTakingAmount, bytes32 orderHash);
}

File 4 of 24 : OrderLib.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

import "@1inch/solidity-utils/contracts/libraries/ECDSA.sol";

library OrderLib {
    struct Order {
        uint256 salt;
        address makerAsset;
        address takerAsset;
        address maker;
        address receiver;
        address allowedSender;  // equals to Zero address on public orders
        uint256 makingAmount;
        uint256 takingAmount;
        uint256 offsets;
        // bytes makerAssetData;
        // bytes takerAssetData;
        // bytes getMakingAmount; // this.staticcall(abi.encodePacked(bytes, swapTakerAmount)) => (swapMakerAmount)
        // bytes getTakingAmount; // this.staticcall(abi.encodePacked(bytes, swapMakerAmount)) => (swapTakerAmount)
        // bytes predicate;       // this.staticcall(bytes) => (bool)
        // bytes permit;          // On first fill: permit.1.call(abi.encodePacked(permit.selector, permit.2))
        // bytes preInteraction;
        // bytes postInteraction;
        bytes interactions; // concat(makerAssetData, takerAssetData, getMakingAmount, getTakingAmount, predicate, permit, preIntercation, postInteraction)
    }

    bytes32 constant internal _LIMIT_ORDER_TYPEHASH = keccak256(
        "Order("
            "uint256 salt,"
            "address makerAsset,"
            "address takerAsset,"
            "address maker,"
            "address receiver,"
            "address allowedSender,"
            "uint256 makingAmount,"
            "uint256 takingAmount,"
            "uint256 offsets,"
            "bytes interactions"
        ")"
    );

    enum DynamicField {
        MakerAssetData,
        TakerAssetData,
        GetMakingAmount,
        GetTakingAmount,
        Predicate,
        Permit,
        PreInteraction,
        PostInteraction
    }

    function getterIsFrozen(bytes calldata getter) internal pure returns(bool) {
        return getter.length == 1 && getter[0] == "x";
    }

    function _get(Order calldata order, DynamicField field) private pure returns(bytes calldata) {
        uint256 bitShift = uint256(field) << 5; // field * 32
        return order.interactions[
            uint32((order.offsets << 32) >> bitShift):
            uint32(order.offsets >> bitShift)
        ];
    }

    function makerAssetData(Order calldata order) internal pure returns(bytes calldata) {
        return _get(order, DynamicField.MakerAssetData);
    }

    function takerAssetData(Order calldata order) internal pure returns(bytes calldata) {
        return _get(order, DynamicField.TakerAssetData);
    }

    function getMakingAmount(Order calldata order) internal pure returns(bytes calldata) {
        return _get(order, DynamicField.GetMakingAmount);
    }

    function getTakingAmount(Order calldata order) internal pure returns(bytes calldata) {
        return _get(order, DynamicField.GetTakingAmount);
    }

    function predicate(Order calldata order) internal pure returns(bytes calldata) {
        return _get(order, DynamicField.Predicate);
    }

    function permit(Order calldata order) internal pure returns(bytes calldata) {
        return _get(order, DynamicField.Permit);
    }

    function preInteraction(Order calldata order) internal pure returns(bytes calldata) {
        return _get(order, DynamicField.PreInteraction);
    }

    function postInteraction(Order calldata order) internal pure returns(bytes calldata) {
        return _get(order, DynamicField.PostInteraction);
    }

    function hash(Order calldata order, bytes32 domainSeparator) internal pure returns(bytes32 result) {
        bytes calldata interactions = order.interactions;
        bytes32 typehash = _LIMIT_ORDER_TYPEHASH;
        /// @solidity memory-safe-assembly
        assembly { // solhint-disable-line no-inline-assembly
            let ptr := mload(0x40)

            // keccak256(abi.encode(_LIMIT_ORDER_TYPEHASH, orderWithoutInteractions, keccak256(order.interactions)));
            calldatacopy(ptr, interactions.offset, interactions.length)
            mstore(add(ptr, 0x140), keccak256(ptr, interactions.length))
            calldatacopy(add(ptr, 0x20), order, 0x120)
            mstore(ptr, typehash)
            result := keccak256(ptr, 0x160)
        }
        result = ECDSA.toTypedDataHash(domainSeparator, result);
    }
}

File 5 of 24 : IDaiLikePermit.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;
pragma abicoder v1;

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

File 6 of 24 : ECDSA.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;
pragma abicoder v1;

import "@openzeppelin/contracts/interfaces/IERC1271.sol";

library ECDSA {
    // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
    // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
    // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
    // signatures from current libraries generate a unique signature with an s-value in the lower half order.
    //
    // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
    // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
    // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
    // these malleable signatures as well.
    uint256 private constant _S_BOUNDARY = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0 + 1;
    uint256 private constant _COMPACT_S_MASK = 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;
    uint256 private constant _COMPACT_V_SHIFT = 255;

    function recover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal view returns (address signer) {
        /// @solidity memory-safe-assembly
        assembly { // solhint-disable-line no-inline-assembly
            if lt(s, _S_BOUNDARY) {
                let ptr := mload(0x40)

                mstore(ptr, hash)
                mstore(add(ptr, 0x20), v)
                mstore(add(ptr, 0x40), r)
                mstore(add(ptr, 0x60), s)
                mstore(0, 0)
                pop(staticcall(gas(), 0x1, ptr, 0x80, 0, 0x20))
                signer := mload(0)
            }
        }
    }

    function recover(
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal view returns (address signer) {
        /// @solidity memory-safe-assembly
        assembly { // solhint-disable-line no-inline-assembly
            let s := and(vs, _COMPACT_S_MASK)
            if lt(s, _S_BOUNDARY) {
                let ptr := mload(0x40)

                mstore(ptr, hash)
                mstore(add(ptr, 0x20), add(27, shr(_COMPACT_V_SHIFT, vs)))
                mstore(add(ptr, 0x40), r)
                mstore(add(ptr, 0x60), s)
                mstore(0, 0)
                pop(staticcall(gas(), 0x1, ptr, 0x80, 0, 0x20))
                signer := mload(0)
            }
        }
    }

    /// @dev WARNING!!!
    /// There is a known signature malleability issue with two representations of signatures!
    /// Even though this function is able to verify both standard 65-byte and compact 64-byte EIP-2098 signatures
    /// one should never use raw signatures for any kind of invalidation logic in their code.
    /// As the standard and compact representations are interchangeable any invalidation logic that relies on
    /// signature uniqueness will get rekt.
    /// More info: https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories/GHSA-4h98-2769-gh6h
    function recover(bytes32 hash, bytes calldata signature) internal view returns (address signer) {
        /// @solidity memory-safe-assembly
        assembly { // solhint-disable-line no-inline-assembly
            let ptr := mload(0x40)

            // memory[ptr:ptr+0x80] = (hash, v, r, s)
            switch signature.length
            case 65 {
                // memory[ptr+0x20:ptr+0x80] = (v, r, s)
                mstore(add(ptr, 0x20), byte(0, calldataload(add(signature.offset, 0x40))))
                calldatacopy(add(ptr, 0x40), signature.offset, 0x40)
            }
            case 64 {
                // memory[ptr+0x20:ptr+0x80] = (v, r, s)
                let vs := calldataload(add(signature.offset, 0x20))
                mstore(add(ptr, 0x20), add(27, shr(_COMPACT_V_SHIFT, vs)))
                calldatacopy(add(ptr, 0x40), signature.offset, 0x20)
                mstore(add(ptr, 0x60), and(vs, _COMPACT_S_MASK))
            }
            default {
                ptr := 0
            }

            if ptr {
                if lt(mload(add(ptr, 0x60)), _S_BOUNDARY) {
                    // memory[ptr:ptr+0x20] = (hash)
                    mstore(ptr, hash)

                    mstore(0, 0)
                    pop(staticcall(gas(), 0x1, ptr, 0x80, 0, 0x20))
                    signer := mload(0)
                }
            }
        }
    }

    function recoverOrIsValidSignature(
        address signer,
        bytes32 hash,
        bytes calldata signature
    ) internal view returns (bool success) {
        if (signer == address(0)) return false;
        if ((signature.length == 64 || signature.length == 65) && recover(hash, signature) == signer) {
            return true;
        }
        return isValidSignature(signer, hash, signature);
    }

    function recoverOrIsValidSignature(
        address signer,
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal view returns (bool success) {
        if (signer == address(0)) return false;
        if (recover(hash, v, r, s) == signer) {
            return true;
        }
        return isValidSignature(signer, hash, v, r, s);
    }

    function recoverOrIsValidSignature(
        address signer,
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal view returns (bool success) {
        if (signer == address(0)) return false;
        if (recover(hash, r, vs) == signer) {
            return true;
        }
        return isValidSignature(signer, hash, r, vs);
    }

    function recoverOrIsValidSignature65(
        address signer,
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal view returns (bool success) {
        if (signer == address(0)) return false;
        if (recover(hash, r, vs) == signer) {
            return true;
        }
        return isValidSignature65(signer, hash, r, vs);
    }

    function isValidSignature(
        address signer,
        bytes32 hash,
        bytes calldata signature
    ) internal view returns (bool success) {
        // (bool success, bytes memory data) = signer.staticcall(abi.encodeWithSelector(IERC1271.isValidSignature.selector, hash, signature));
        // return success && data.length >= 4 && abi.decode(data, (bytes4)) == IERC1271.isValidSignature.selector;
        bytes4 selector = IERC1271.isValidSignature.selector;
        /// @solidity memory-safe-assembly
        assembly { // solhint-disable-line no-inline-assembly
            let ptr := mload(0x40)

            mstore(ptr, selector)
            mstore(add(ptr, 0x04), hash)
            mstore(add(ptr, 0x24), 0x40)
            mstore(add(ptr, 0x44), signature.length)
            calldatacopy(add(ptr, 0x64), signature.offset, signature.length)
            if staticcall(gas(), signer, ptr, add(0x64, signature.length), 0, 0x20) {
                success := and(eq(selector, mload(0)), eq(returndatasize(), 0x20))
            }
        }
    }

    function isValidSignature(
        address signer,
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal view returns (bool success) {
        bytes4 selector = IERC1271.isValidSignature.selector;
        /// @solidity memory-safe-assembly
        assembly { // solhint-disable-line no-inline-assembly
            let ptr := mload(0x40)

            mstore(ptr, selector)
            mstore(add(ptr, 0x04), hash)
            mstore(add(ptr, 0x24), 0x40)
            mstore(add(ptr, 0x44), 65)
            mstore(add(ptr, 0x64), r)
            mstore(add(ptr, 0x84), s)
            mstore8(add(ptr, 0xa4), v)
            if staticcall(gas(), signer, ptr, 0xa5, 0, 0x20) {
                success := and(eq(selector, mload(0)), eq(returndatasize(), 0x20))
            }
        }
    }

    function isValidSignature(
        address signer,
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal view returns (bool success) {
        // (bool success, bytes memory data) = signer.staticcall(abi.encodeWithSelector(IERC1271.isValidSignature.selector, hash, abi.encodePacked(r, vs)));
        // return success && data.length >= 4 && abi.decode(data, (bytes4)) == IERC1271.isValidSignature.selector;
        bytes4 selector = IERC1271.isValidSignature.selector;
        /// @solidity memory-safe-assembly
        assembly { // solhint-disable-line no-inline-assembly
            let ptr := mload(0x40)

            mstore(ptr, selector)
            mstore(add(ptr, 0x04), hash)
            mstore(add(ptr, 0x24), 0x40)
            mstore(add(ptr, 0x44), 64)
            mstore(add(ptr, 0x64), r)
            mstore(add(ptr, 0x84), vs)
            if staticcall(gas(), signer, ptr, 0xa4, 0, 0x20) {
                success := and(eq(selector, mload(0)), eq(returndatasize(), 0x20))
            }
        }
    }

    function isValidSignature65(
        address signer,
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal view returns (bool success) {
        // (bool success, bytes memory data) = signer.staticcall(abi.encodeWithSelector(IERC1271.isValidSignature.selector, hash, abi.encodePacked(r, vs & ~uint256(1 << 255), uint8(vs >> 255))));
        // return success && data.length >= 4 && abi.decode(data, (bytes4)) == IERC1271.isValidSignature.selector;
        bytes4 selector = IERC1271.isValidSignature.selector;
        /// @solidity memory-safe-assembly
        assembly { // solhint-disable-line no-inline-assembly
            let ptr := mload(0x40)

            mstore(ptr, selector)
            mstore(add(ptr, 0x04), hash)
            mstore(add(ptr, 0x24), 0x40)
            mstore(add(ptr, 0x44), 65)
            mstore(add(ptr, 0x64), r)
            mstore(add(ptr, 0x84), and(vs, _COMPACT_S_MASK))
            mstore8(add(ptr, 0xa4), add(27, shr(_COMPACT_V_SHIFT, vs)))
            if staticcall(gas(), signer, ptr, 0xa5, 0, 0x20) {
                success := and(eq(selector, mload(0)), eq(returndatasize(), 0x20))
            }
        }
    }

    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 res) {
        // 32 is the length in bytes of hash, enforced by the type signature above
        // return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
        /// @solidity memory-safe-assembly
        assembly { // solhint-disable-line no-inline-assembly
            mstore(0, 0x19457468657265756d205369676e6564204d6573736167653a0a333200000000) // "\x19Ethereum Signed Message:\n32"
            mstore(28, hash)
            res := keccak256(0, 60)
        }
    }

    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 res) {
        // return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
        /// @solidity memory-safe-assembly
        assembly { // solhint-disable-line no-inline-assembly
            let ptr := mload(0x40)
            mstore(ptr, 0x1901000000000000000000000000000000000000000000000000000000000000) // "\x19\x01"
            mstore(add(ptr, 0x02), domainSeparator)
            mstore(add(ptr, 0x22), structHash)
            res := keccak256(ptr, 66)
        }
    }
}

File 7 of 24 : RevertReasonForwarder.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;
pragma abicoder v1;

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

File 8 of 24 : SafeERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;
pragma abicoder v1;

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

/// @title Implements efficient safe methods for ERC20 interface.
library SafeERC20 {
    error SafeTransferFailed();
    error SafeTransferFromFailed();
    error ForceApproveFailed();
    error SafeIncreaseAllowanceFailed();
    error SafeDecreaseAllowanceFailed();
    error SafePermitBadLength();

    /// @dev Ensures method do not revert or return boolean `true`, admits call to non-smart-contract.
    function safeTransferFrom(
        IERC20 token,
        address from,
        address to,
        uint256 amount
    ) internal {
        bytes4 selector = token.transferFrom.selector;
        bool success;
        /// @solidity memory-safe-assembly
        assembly { // 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();
    }

    /// @dev Ensures method do not revert or return boolean `true`, admits call to non-smart-contract.
    function safeTransfer(
        IERC20 token,
        address to,
        uint256 value
    ) internal {
        if (!_makeCall(token, token.transfer.selector, to, value)) {
            revert SafeTransferFailed();
        }
    }

    /// @dev If `approve(from, to, amount)` fails, try to `approve(from, to, 0)` before retry.
    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();
            }
        }
    }

    /// @dev Allowance increase with safe math check.
    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);
    }

    /// @dev Allowance decrease with safe math check.
    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);
    }

    /// @dev Calls either ERC20 or Dai `permit` for `token`, if unsuccessful forwards revert from external call.
    function safePermit(IERC20 token, bytes calldata permit) internal {
        if (!tryPermit(token, permit)) RevertReasonForwarder.reRevert();
    }

    function tryPermit(IERC20 token, bytes calldata permit) internal returns(bool) {
        if (permit.length == 32 * 7) {
            return _makeCalldataCall(token, IERC20Permit.permit.selector, permit);
        }
        if (permit.length == 32 * 8) {
            return _makeCalldataCall(token, IDaiLikePermit.permit.selector, permit);
        }
        revert SafePermitBadLength();
    }

    function _makeCall(
        IERC20 token,
        bytes4 selector,
        address to,
        uint256 amount
    ) private returns (bool success) {
        /// @solidity memory-safe-assembly
        assembly { // 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))
                }
            }
        }
    }

    function _makeCalldataCall(
        IERC20 token,
        bytes4 selector,
        bytes calldata args
    ) private returns (bool success) {
        /// @solidity memory-safe-assembly
        assembly { // solhint-disable-line no-inline-assembly
            let len := add(4, args.length)
            let data := mload(0x40)

            mstore(data, selector)
            calldatacopy(add(data, 0x04), args.offset, args.length)
            success := call(gas(), token, 0, data, len, 0x0, 0x20)
            if success {
                switch returndatasize()
                case 0 {
                    success := gt(extcodesize(token), 0)
                }
                default {
                    success := and(gt(returndatasize(), 31), eq(mload(0), 1))
                }
            }
        }
    }
}

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

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

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

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

File 10 of 24 : IERC1271.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC1271.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC1271 standard signature validation method for
 * contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271].
 *
 * _Available since v4.1._
 */
interface IERC1271 {
    /**
     * @dev Should return whether the signature provided is valid for the provided data
     * @param hash      Hash of the data to be signed
     * @param signature Signature byte array associated with _data
     */
    function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue);
}

File 11 of 24 : draft-IERC20Permit.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)

pragma solidity ^0.8.0;

/**
 * @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.
 */
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].
     */
    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 12 of 24 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

File 13 of 24 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

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

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

File 14 of 24 : FeeBank.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

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

/// @title Contract with fee mechanism for solvers to pay for using the system
contract FeeBank is IFeeBank, Ownable {
    using SafeERC20 for IERC20;

    IERC20 private immutable _token;
    IFeeBankCharger private immutable _charger;

    mapping(address => uint256) private _accountDeposits;

    constructor(IFeeBankCharger charger, IERC20 inch, address owner) {
        _charger = charger;
        _token = inch;
        transferOwnership(owner);
    }

    function availableCredit(address account) external view returns (uint256) {
        return _charger.availableCredit(account);
    }

    /**
     * @notice Increment sender's availableCredit in Settlement contract.
     * @param amount The amount of 1INCH sender pay for incresing.
     * @return totalAvailableCredit The total sender's availableCredit after deposit.
     */
    function deposit(uint256 amount) external returns (uint256 totalAvailableCredit) {
        return _depositFor(msg.sender, amount);
    }

    /**
     * @notice Increases account's availableCredit in Settlement contract.
     * @param account The account whose availableCredit is increased by the sender.
     * @param amount The amount of 1INCH sender pay for incresing.
     * @return totalAvailableCredit The total account's availableCredit after deposit.
     */
    function depositFor(address account, uint256 amount) external returns (uint256 totalAvailableCredit) {
        return _depositFor(account, amount);
    }

    /**
     * @notice See {deposit}. This method uses permit for deposit without prior approves.
     * @param amount The amount of 1INCH sender pay for incresing.
     * @param permit The data with sender's permission via token.
     * @return totalAvailableCredit The total sender's availableCredit after deposit.
     */
    function depositWithPermit(uint256 amount, bytes calldata permit) external returns (uint256 totalAvailableCredit) {
        return depositForWithPermit(msg.sender, amount, permit);
    }

    /**
     * @notice See {depositFor} and {depositWithPermit}.
     */
    function depositForWithPermit(
        address account,
        uint256 amount,
        bytes calldata permit
    ) public returns (uint256 totalAvailableCredit) {
        _token.safePermit(permit);
        return _depositFor(account, amount);
    }

    /**
     * @notice Returns unspent availableCredit.
     * @param amount The amount of 1INCH sender returns.
     * @return totalAvailableCredit The total sender's availableCredit after withdrawal.
     */
    function withdraw(uint256 amount) external returns (uint256 totalAvailableCredit) {
        return _withdrawTo(msg.sender, amount);
    }

    /**
     * @notice Returns unspent availableCredit to specific account.
     * @param account The account which get withdrawaled tokens.
     * @param amount The amount of withdrawaled tokens.
     * @return totalAvailableCredit The total sender's availableCredit after withdrawal.
     */
    function withdrawTo(address account, uint256 amount) external returns (uint256 totalAvailableCredit) {
        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[] memory accounts) external onlyOwner returns (uint256 totalAccountFees) {
        uint256 accountsLength = accounts.length;
        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_;
        }
        _token.safeTransfer(msg.sender, totalAccountFees);
    }

    function _depositFor(address account, uint256 amount) internal returns (uint256 totalAvailableCredit) {
        _token.safeTransferFrom(msg.sender, address(this), amount);
        _accountDeposits[account] += amount;
        totalAvailableCredit = _charger.increaseAvailableCredit(account, amount);
    }

    function _withdrawTo(address account, uint256 amount) internal returns (uint256 totalAvailableCredit) {
        totalAvailableCredit = _charger.decreaseAvailableCredit(msg.sender, amount);
        _accountDeposits[msg.sender] -= amount;
        _token.safeTransfer(account, amount);
    }
}

File 15 of 24 : FeeBankCharger.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

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

contract FeeBankCharger is IFeeBankCharger {
    error OnlyFeeBankAccess();
    error NotEnoughCredit();

    IFeeBank public immutable feeBank;
    mapping(address => uint256) private _creditAllowance;

    modifier onlyFeeBank() {
        if (msg.sender != address(feeBank)) revert OnlyFeeBankAccess();
        _;
    }

    constructor(IERC20 token) {
        feeBank = new FeeBank(this, token, msg.sender);
    }

    function availableCredit(address account) external view returns (uint256) {
        return _creditAllowance[account];
    }

    function increaseAvailableCredit(address account, uint256 amount) external onlyFeeBank returns (uint256 allowance) {
        allowance = _creditAllowance[account];
        allowance += amount;
        _creditAllowance[account] = allowance;
    }

    function decreaseAvailableCredit(address account, uint256 amount) external onlyFeeBank returns (uint256 allowance) {
        allowance = _creditAllowance[account];
        allowance -= amount;
        _creditAllowance[account] = allowance;
    }

    function _chargeFee(address account, uint256 fee) internal {
        if (fee > 0) {
            uint256 currentAllowance = _creditAllowance[account];
            if (currentAllowance < fee) revert NotEnoughCredit();
            unchecked {
                _creditAllowance[account] = currentAllowance - fee;
            }
        }
    }
}

File 16 of 24 : IFeeBank.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

interface IFeeBank {
    function deposit(uint256 amount) external returns (uint256 totalAvailableCredit);
}

File 17 of 24 : IFeeBankCharger.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

interface IFeeBankCharger {
    function availableCredit(address account) external view returns (uint256);
    function increaseAvailableCredit(address account, uint256 amount) external returns (uint256 allowance);
    function decreaseAvailableCredit(address account, uint256 amount) external returns (uint256 allowance);
}

File 18 of 24 : IResolver.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

import "../libraries/DynamicSuffix.sol";

interface IResolver {
    function resolveOrders(address resolver, bytes calldata tokensAndAmounts, bytes calldata data) external;
}

File 19 of 24 : ISettlement.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

import "@1inch/limit-order-protocol-contract/contracts/interfaces/IInteractionNotificationReceiver.sol";
import "./IFeeBankCharger.sol";

interface ISettlement is IInteractionNotificationReceiver, IFeeBankCharger {
    function settleOrders(bytes calldata order) external;
}

File 20 of 24 : Address.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

type Address is uint256;

library AddressLib {
    function get(Address a) internal pure returns (address) {
        return address(uint160(Address.unwrap(a)));
    }

    function getFlag(Address a, uint256 flag) internal pure returns (bool) {
        return Address.unwrap(a) & flag != 0;
    }

    function getUint32(Address a, uint256 offset) internal pure returns (uint32) {
        return uint32(Address.unwrap(a) >> offset);
    }

    function getUint64(Address a, uint256 offset) internal pure returns (uint64) {
        return uint64(Address.unwrap(a) >> offset);
    }
}

File 21 of 24 : DynamicSuffix.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

import "./Address.sol";
import "./TakingFee.sol";

// layout of dynamic suffix is as follows:
// 0x00 - 0x19: totalFee
// 0x20 - 0x39: resolver
// 0x40 - 0x59: token
// 0x60 - 0x79: rateBump
// 0x80 - 0x99: takingFee
// 0xa0 - 0x..: tokensAndAmounts bytes
// 0x.. - 0x..: tokensAndAmounts length in bytes
library DynamicSuffix {
    struct Data {
        uint256 totalFee;
        Address resolver;
        Address token;
        uint256 rateBump;
        TakingFee.Data takingFee;
    }

    uint256 internal constant _STATIC_DATA_SIZE = 0xa0;

    function decodeSuffix(bytes calldata cd) internal pure returns(Data calldata suffix, bytes calldata tokensAndAmounts, bytes calldata interaction) {
        assembly {
            let lengthOffset := sub(add(cd.offset, cd.length), 0x20)
            tokensAndAmounts.length := calldataload(lengthOffset)
            tokensAndAmounts.offset := sub(lengthOffset, tokensAndAmounts.length)
            suffix := sub(tokensAndAmounts.offset, _STATIC_DATA_SIZE)
            interaction.offset := add(cd.offset, 1)
            interaction.length := sub(suffix, interaction.offset)
        }
    }
}

File 22 of 24 : OrderSaltParser.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

/// @title Library for parsing parameters from salt.
library OrderSaltParser {
    uint256 private constant _TIME_START_MASK        = 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000; // prettier-ignore
    uint256 private constant _DURATION_MASK          = 0x00000000FFFFFF00000000000000000000000000000000000000000000000000; // prettier-ignore
    uint256 private constant _INITIAL_RATE_BUMP_MASK = 0x00000000000000FFFFFF00000000000000000000000000000000000000000000; // prettier-ignore
    uint256 private constant _FEE_MASK               = 0x00000000000000000000FFFFFFFF000000000000000000000000000000000000; // prettier-ignore
    uint256 private constant _SALT_MASK              = 0x0000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // prettier-ignore

    uint256 private constant _TIME_START_SHIFT = 224; // orderTimeMask 224-255
    uint256 private constant _DURATION_SHIFT = 200; // durationMask 200-223
    uint256 private constant _INITIAL_RATE_BUMP_SHIFT = 176; // initialRateMask 176-200
    uint256 private constant _FEE_SHIFT = 144; // orderFee 144-175

    function getStartTime(uint256 salt) internal pure returns (uint256) {
        return (salt & _TIME_START_MASK) >> _TIME_START_SHIFT;
    }

    function getDuration(uint256 salt) internal pure returns (uint256) {
        return (salt & _DURATION_MASK) >> _DURATION_SHIFT;
    }

    function getInitialRateBump(uint256 salt) internal pure returns (uint256) {
        return (salt & _INITIAL_RATE_BUMP_MASK) >> _INITIAL_RATE_BUMP_SHIFT;
    }

    function getFee(uint256 salt) internal pure returns (uint256) {
        return (salt & _FEE_MASK) >> _FEE_SHIFT;
    }

    function getSalt(uint256 salt) internal pure returns (uint256) {
        return salt & _SALT_MASK;
    }
}

File 23 of 24 : OrderSuffix.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

import "@1inch/limit-order-protocol-contract/contracts/OrderLib.sol";
import "./OrderSaltParser.sol";
import "./TakingFee.sol";

// Placed in the end of the order interactions data
// Last byte contains flags and lengths, can have up to 15 resolvers and 7 points
library OrderSuffix {
    using OrderSaltParser for uint256;

    // `Order.interactions` suffix structure:
    // M*(1 + 3 bytes)  - auction points coefficients with seconds delays
    // N*(4 + 20 bytes) - resolver with corresponding time limit
    // 4 bytes          - public time limit
    // 32 bytes         - taking fee (optional if flags has _HAS_TAKING_FEE_FLAG)
    // 1 bytes          - flags

    uint256 private constant _HAS_TAKING_FEE_FLAG = 0x80;
    uint256 private constant _RESOLVERS_LENGTH_MASK = 0x78;
    uint256 private constant _RESOLVERS_LENGTH_BIT_SHIFT = 3;
    uint256 private constant _POINTS_LENGTH_MASK = 0x07;
    uint256 private constant _POINTS_LENGTH_BIT_SHIFT = 0;

    uint256 private constant _TAKING_FEE_BYTES_SIZE = 32;

    uint256 private constant _PUBLIC_TIME_LIMIT_BYTES_SIZE = 4;
    uint256 private constant _PUBLIC_TIME_LIMIT_BIT_SHIFT = 224; // 256 - _PUBLIC_TIME_LIMIT_BYTES_SIZE * 8

    uint256 private constant _AUCTION_POINT_DELAY_BYTES_SIZE = 2;
    uint256 private constant _AUCTION_POINT_BUMP_BYTES_SIZE = 3;
    uint256 private constant _AUCTION_POINT_BYTES_SIZE = 5; // _AUCTION_POINT_DELAY_BYTES_SIZE + _AUCTION_POINT_BUMP_BYTES_SIZE;
    uint256 private constant _AUCTION_POINT_DELAY_BIT_SHIFT = 240; // 256 - _AUCTION_POINT_DELAY_BYTES_SIZE * 8;
    uint256 private constant _AUCTION_POINT_BUMP_BIT_SHIFT = 232; // 256 - _AUCTION_POINT_BUMP_BYTES_SIZE * 8;

    uint256 private constant _RESOLVER_TIME_LIMIT_BYTES_SIZE = 4;
    uint256 private constant _RESOLVER_ADDRESS_BYTES_SIZE = 20;
    uint256 private constant _RESOLVER_BYTES_SIZE = 24; // _RESOLVER_TIME_LIMIT_BYTES_SIZE + _RESOLVER_ADDRESS_BYTES_SIZE;
    uint256 private constant _RESOLVER_TIME_LIMIT_BIT_SHIFT = 224; // 256 - _RESOLVER_TIME_LIMIT_BYTES_SIZE * 8;
    uint256 private constant _RESOLVER_ADDRESS_BIT_SHIFT = 96; // 256 - _RESOLVER_ADDRESS_BYTES_SIZE * 8;

    function takingFee(OrderLib.Order calldata order) internal pure returns (TakingFee.Data ret) {
        bytes calldata interactions = order.interactions;
        assembly {
            let ptr := sub(add(interactions.offset, interactions.length), 1)
            if and(_HAS_TAKING_FEE_FLAG, byte(0, calldataload(ptr))) {
                ret := calldataload(sub(ptr, _TAKING_FEE_BYTES_SIZE))
            }
        }
    }

    function checkResolver(OrderLib.Order calldata order, address resolver) internal view returns (bool valid) {
        bytes calldata interactions = order.interactions;
        assembly {
            let ptr := sub(add(interactions.offset, interactions.length), 1)
            let flags := byte(0, calldataload(ptr))
            ptr := sub(ptr, _PUBLIC_TIME_LIMIT_BYTES_SIZE)
            if and(flags, _HAS_TAKING_FEE_FLAG) {
                ptr := sub(ptr, _TAKING_FEE_BYTES_SIZE)
            }

            let resolversCount := shr(_RESOLVERS_LENGTH_BIT_SHIFT, and(flags, _RESOLVERS_LENGTH_MASK))

            // Check public time limit
            let publicLimit := shr(_PUBLIC_TIME_LIMIT_BIT_SHIFT, calldataload(ptr))
            valid := gt(timestamp(), publicLimit)

            // Check resolvers and corresponding time limits
            if not(valid) {
                for { let end := sub(ptr, mul(_RESOLVER_BYTES_SIZE, resolversCount)) } gt(ptr, end) { } {
                    ptr := sub(ptr, _RESOLVER_ADDRESS_BYTES_SIZE)
                    let account := shr(_RESOLVER_ADDRESS_BIT_SHIFT, calldataload(ptr))
                    ptr := sub(ptr, _RESOLVER_TIME_LIMIT_BYTES_SIZE)
                    let limit := shr(_RESOLVER_TIME_LIMIT_BIT_SHIFT, calldataload(ptr))
                    if eq(account, resolver) {
                        valid := iszero(lt(timestamp(), limit))
                        break
                    }
                }
            }
        }
    }

    function rateBump(OrderLib.Order calldata order) internal view returns (uint256 bump) {
        uint256 startBump = order.salt.getInitialRateBump();
        uint256 cumulativeTime = order.salt.getStartTime();
        uint256 lastTime = cumulativeTime + order.salt.getDuration();
        if (block.timestamp <= cumulativeTime) {
            return startBump;
        } else if (block.timestamp >= lastTime) {
            return 0;
        }

        bytes calldata interactions = order.interactions;
        assembly {
            function linearInterpolation(t1, t2, v1, v2, t) -> v {
                v := div(
                    add(mul(sub(t, t1), v2), mul(sub(t2, t), v1)),
                    sub(t2, t1)
                )
            }

            let ptr := sub(add(interactions.offset, interactions.length), 1)

            // move ptr to the last point
            let pointsCount
            {  // stack too deep
                let flags := byte(0, calldataload(ptr))
                let resolversCount := shr(_RESOLVERS_LENGTH_BIT_SHIFT, and(flags, _RESOLVERS_LENGTH_MASK))
                pointsCount := and(flags, _POINTS_LENGTH_MASK)
                if and(flags, _HAS_TAKING_FEE_FLAG) {
                    ptr := sub(ptr, _TAKING_FEE_BYTES_SIZE)
                }
                ptr := sub(ptr, add(mul(_RESOLVER_BYTES_SIZE, resolversCount), _PUBLIC_TIME_LIMIT_BYTES_SIZE)) // 24 byte for each wl entry + 4 bytes for public time limit
            }

            // Check points sequentially
            let prevCoefficient := startBump
            let prevCumulativeTime := cumulativeTime
            for { let end := sub(ptr, mul(_AUCTION_POINT_BYTES_SIZE, pointsCount)) } gt(ptr, end) { } {
                ptr := sub(ptr, _AUCTION_POINT_BUMP_BYTES_SIZE)
                let coefficient := shr(_AUCTION_POINT_BUMP_BIT_SHIFT, calldataload(ptr))
                ptr := sub(ptr, _AUCTION_POINT_DELAY_BYTES_SIZE)
                let delay := shr(_AUCTION_POINT_DELAY_BIT_SHIFT, calldataload(ptr))
                cumulativeTime := add(cumulativeTime, delay)
                if gt(cumulativeTime, timestamp()) {
                    // prevCumulativeTime <passed> time <elapsed> cumulativeTime
                    // prevCoefficient    <passed>  X   <elapsed> coefficient
                    bump := linearInterpolation(
                        prevCumulativeTime,
                        cumulativeTime,
                        prevCoefficient,
                        coefficient,
                        timestamp()
                    )
                    break
                }
                prevCumulativeTime := cumulativeTime
                prevCoefficient := coefficient
            }

            if iszero(bump) {
                bump := linearInterpolation(
                    prevCumulativeTime,
                    lastTime,
                    prevCoefficient,
                    0,
                    timestamp()
                )
            }
        }
    }
}

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

pragma solidity 0.8.17;

library TakingFee {
    type Data is uint256;

    uint256 internal constant _TAKING_FEE_BASE = 1e9;
    uint256 private constant _TAKING_FEE_RATIO_OFFSET = 160;

    function init(address receiver_, uint256 ratio_) internal pure returns (Data) {
        if (ratio_ == 0) {
            return Data.wrap(uint160(receiver_));
        }
        return Data.wrap(uint160(receiver_) | (ratio_ << _TAKING_FEE_RATIO_OFFSET));
    }

    function enabled(Data self) internal pure returns (bool) {
        return ratio(self) != 0;
    }

    function ratio(Data self) internal pure returns (uint256) {
        return uint32(Data.unwrap(self) >> _TAKING_FEE_RATIO_OFFSET);
    }

    function receiver(Data self) internal pure returns (address) {
        return address(uint160(Data.unwrap(self)));
    }
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"contract IOrderMixin","name":"limitOrderProtocol","type":"address"},{"internalType":"contract IERC20","name":"token","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessDenied","type":"error"},{"inputs":[],"name":"FailedExternalCall","type":"error"},{"inputs":[],"name":"ForceApproveFailed","type":"error"},{"inputs":[],"name":"IncorrectCalldataParams","type":"error"},{"inputs":[],"name":"NotEnoughCredit","type":"error"},{"inputs":[],"name":"OnlyFeeBankAccess","type":"error"},{"inputs":[],"name":"ResolverIsNotWhitelisted","type":"error"},{"inputs":[],"name":"SafeTransferFailed","type":"error"},{"inputs":[],"name":"WrongInteractionTarget","type":"error"},{"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":[],"name":"feeBank","outputs":[{"internalType":"contract IFeeBank","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"taker","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"takingAmount","type":"uint256"},{"internalType":"bytes","name":"interactiveData","type":"bytes"}],"name":"fillOrderInteraction","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"nonpayable","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":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"settleOrders","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60c060405234801561001057600080fd5b50604051620023a0380380620023a0833981016040819052610031916100c1565b803081336040516100419061009b565b6001600160a01b03938416815291831660208301529091166040820152606001604051809103906000f08015801561007d573d6000803e3d6000fd5b506001600160a01b039081166080529290921660a052506100fb9050565b611120806200128083390190565b6001600160a01b03811681146100be57600080fd5b50565b600080604083850312156100d457600080fd5b82516100df816100a9565b60208401519092506100f0816100a9565b809150509250929050565b60805160a0516111436200013d6000396000818161035b015281816106a4015261077f01526000818161010001528181610197015261026901526111436000f3fe608060405234801561001057600080fd5b50600436106100725760003560e01c806385eda2de1161005057806385eda2de146100e8578063af15d786146100fb578063ccee33d71461014757600080fd5b80630965d04b146100775780633ee5ef1f1461008c5780635886216f146100b2575b600080fd5b61008a610085366004610d52565b61015a565b005b61009f61009a366004610dbd565b61017d565b6040519081526020015b60405180910390f35b61009f6100c0366004610de7565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b61009f6100f6366004610dbd565b61024f565b6101227f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100a9565b61009f610155366004610e09565b6102f1565b60408051600080825260208201909252610179918491849133916106db565b5050565b60003373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146101ee576040517fa454419900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5073ffffffffffffffffffffffffffffffffffffffff821660009081526020819052604090205461021f8282610ecf565b73ffffffffffffffffffffffffffffffffffffffff90931660009081526020819052604090208390555090919050565b60003373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146102c0576040517fa454419900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5073ffffffffffffffffffffffffffffffffffffffff821660009081526020819052604090205461021f8282610ee8565b60008573ffffffffffffffffffffffffffffffffffffffff81163014610343576040517f4ca8886700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146103b2576040517f4ca8886700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8284017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081810135918290037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff40810192918101919060018801908881037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3f01907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80810135906298968090610489907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0013582610ecf565b610493908d610efb565b61049d9190610f12565b97506000633b9aca006104bd63ffffffff60808a013560a01c168b610efb565b6104c79190610f12565b905060006104d6866040610ecf565b67ffffffffffffffff8111156104ee576104ee610e71565b6040519080825280601f01601f191660200182016040528015610518576020820181803683370190505b509050602081018688823786018381528a83016020909101527f01000000000000000000000000000000000000000000000000000000000000008c8c60008161056357610563610f4d565b9050013560f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19160361064b576105a3602089013589356108a3565b60006105af8587610f7c565b60601c90503660006105c4876014818b610fc4565b915091508273ffffffffffffffffffffffffffffffffffffffff16631944799f6105ef8d6020013590565b8685856040518563ffffffff1660e01b81526004016106119493929190610fee565b600060405180830381600087803b15801561062b57600080fd5b505af115801561063f573d6000803e3d6000fd5b5050505050505061065d565b61065d858560208b01358b35856106db565b81156106885761068873ffffffffffffffffffffffffffffffffffffffff841660808a013584610936565b6106c973ffffffffffffffffffffffffffffffffffffffff84167f00000000000000000000000000000000000000000000000000000000000000008c61099d565b50505050505050505095945050505050565b843585016106e98185610a66565b61071f576040517f4b57606900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061072a82610b37565b905061074766038d7ea4c6800063ffffffff843560901c16610efb565b6107519085610ecf565b9350600061075e83610b70565b90506000845160a06107709190610ecf565b61077b906020610ecf565b90507f00000000000000000000000000000000000000000000000000000000000000006107b1565b8281848460045afa50505050565b60408a013560208101818c0135818d013560601c308114156014831017156107fd577f5b34bf890000000000000000000000000000000000000000000000000000000060005260046000fd5b506040517fe5d7bde60000000000000000000000000000000000000000000000000000000081528c8e600483013785820160048583010152818382010193508a60048501528b60248501526040890135604485015286606485015287608485015289516108718160208d0160a488016107a3565b84810160a40152600081878f016004018183895af1610893573d6000823e3d81fd5b5050505050505050505050505050565b80156101795773ffffffffffffffffffffffffffffffffffffffff821660009081526020819052604090205481811015610909576040517fa7fd379200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff92909216600090815260208190526040902091039055565b610962837fa9059cbb000000000000000000000000000000000000000000000000000000008484610cb5565b610998576040517ffb7f507900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050565b6109c9837f095ea7b3000000000000000000000000000000000000000000000000000000008484610cb5565b610998576109fa837f095ea7b300000000000000000000000000000000000000000000000000000000846000610cb5565b1580610a2f5750610a2d837f095ea7b3000000000000000000000000000000000000000000000000000000008484610cb5565b155b15610998576040517f19be9a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60003681610a786101208601866110a8565b91509150600181830103803560001a6004820391506080811615610a9d576020820391505b813560e01c4211945060031c600f16841915610b2d578060180282035b80831115610b2b577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe88301927fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec013560601c833560e01c888203610b24574210159650610b2b9050565b5050610aba565b505b5050505092915050565b60003681610b496101208501856110a8565b91509150600181830103803560001a60801615610b6857602081033593505b505050919050565b600062ffffff823560b081901c82169160e082901c918491610b969160c81c1683610ecf565b9050814211610ba85750909392505050565b804210610bba57506000949350505050565b366000610bcb6101208801886110a8565b915091506001818301036000813560001a6078811660031c6007821692506080821615610bf9576020840393505b6004816018020184039350505086868260050284035b80851115610c95577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb8501803560f01c9990990198947ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd013560e81c428a1115610c8b57828a03428481038302908c03860201049b5050610c95565b9250889150610c0f565b5089610ca75780870342880383020499505b505050505050505050919050565b60006040518481528360048201528260248201526020600060448360008a5af19150508015610d01573d8015610cf757600160005114601f3d11169150610cff565b6000863b1191505b505b949350505050565b60008083601f840112610d1b57600080fd5b50813567ffffffffffffffff811115610d3357600080fd5b602083019150836020828501011115610d4b57600080fd5b9250929050565b60008060208385031215610d6557600080fd5b823567ffffffffffffffff811115610d7c57600080fd5b610d8885828601610d09565b90969095509350505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610db857600080fd5b919050565b60008060408385031215610dd057600080fd5b610dd983610d94565b946020939093013593505050565b600060208284031215610df957600080fd5b610e0282610d94565b9392505050565b600080600080600060808688031215610e2157600080fd5b610e2a86610d94565b94506020860135935060408601359250606086013567ffffffffffffffff811115610e5457600080fd5b610e6088828901610d09565b969995985093965092949392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610ee257610ee2610ea0565b92915050565b81810381811115610ee257610ee2610ea0565b8082028115828204841417610ee257610ee2610ea0565b600082610f48577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008135818116916014851015610fbc5780818660140360031b1b83161692505b505092915050565b60008085851115610fd457600080fd5b83861115610fe157600080fd5b5050820193919092039150565b73ffffffffffffffffffffffffffffffffffffffff8516815260006020606081840152855180606085015260005b818110156110385787810183015185820160800152820161101c565b506000608082860101527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0915081601f820116840190506080848203016040850152846080820152848660a0830137600060a0868301015260a082601f8701168201019250505095945050505050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126110dd57600080fd5b83018035915067ffffffffffffffff8211156110f857600080fd5b602001915036819003821315610d4b57600080fdfea26469706673582212209c7fa27ec20c16ed309e2009a17458ca2682f2e05f31b135d716c14e5c5730f464736f6c6343000811003360c06040523480156200001157600080fd5b5060405162001120380380620011208339810160408190526200003491620001ad565b6200003f3362000066565b6001600160a01b0380841660a05282166080526200005d81620000b6565b50505062000201565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b620000c062000139565b6001600160a01b0381166200012b5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b620001368162000066565b50565b6000546001600160a01b03163314620001955760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640162000122565b565b6001600160a01b03811681146200013657600080fd5b600080600060608486031215620001c357600080fd5b8351620001d08162000197565b6020850151909350620001e38162000197565b6040850151909250620001f68162000197565b809150509250925092565b60805160a051610ecf620002516000396000818161028b015281816103a0015281816105c101526107780152600081816102070152818161047c0152818161068701526106ca0152610ecf6000f3fe608060405234801561001057600080fd5b50600436106100c95760003560e01c8063715018a611610081578063b6b55f251161005b578063b6b55f2514610185578063bfe9173414610198578063f2fde38b146101ab57600080fd5b8063715018a6146101405780638da5cb5b1461014a57806397a2cb641461017257600080fd5b80632f4f21e2116100b25780632f4f21e21461010757806332d323a51461011a5780635886216f1461012d57600080fd5b8063205c2878146100ce5780632e1a7d4d146100f4575b600080fd5b6100e16100dc366004610b65565b6101be565b6040519081526020015b60405180910390f35b6100e1610102366004610b8f565b6101d3565b6100e1610115366004610b65565b6101df565b6100e1610128366004610bf1565b6101eb565b6100e161013b366004610c4b565b610243565b6101486102f8565b005b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100eb565b6100e1610180366004610c95565b61030c565b6100e1610193366004610b8f565b6104a9565b6100e16101a6366004610d78565b6104b5565b6101486101b9366004610c4b565b6104cd565b60006101ca8383610589565b90505b92915050565b60006101cd3383610589565b60006101ca83836106ae565b600061022e73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001684846107e5565b61023885856106ae565b90505b949350505050565b6040517f5886216f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301526000917f000000000000000000000000000000000000000000000000000000000000000090911690635886216f90602401602060405180830381865afa1580156102d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101cd9190610dc4565b610300610801565b61030a6000610882565b565b6000610316610801565b815160005b8181101561046157600084828151811061033757610337610ddd565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff8082166000818152600190945260408085205490517f5886216f00000000000000000000000000000000000000000000000000000000815260048101929092529294509192917f000000000000000000000000000000000000000000000000000000000000000090911690635886216f90602401602060405180830381865afa1580156103e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061040d9190610dc4565b73ffffffffffffffffffffffffffffffffffffffff8416600090815260016020526040902081905590506104418183610e3b565b61044b9087610e4e565b95505050508061045a90610e61565b905061031b565b506104a373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001633846108f7565b50919050565b60006101cd33836106ae565b60006104c3338585856101eb565b90505b9392505050565b6104d5610801565b73ffffffffffffffffffffffffffffffffffffffff811661057d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b61058681610882565b50565b6040517f85eda2de000000000000000000000000000000000000000000000000000000008152336004820152602481018290526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906385eda2de906044016020604051808303816000875af115801561061f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106439190610dc4565b33600090815260016020526040812080549293508492909190610667908490610e3b565b909155506101cd905073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001684846108f7565b60006106f273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016333085610959565b73ffffffffffffffffffffffffffffffffffffffff831660009081526001602052604081208054849290610727908490610e4e565b90915550506040517f3ee5ef1f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152602482018490527f00000000000000000000000000000000000000000000000000000000000000001690633ee5ef1f906044016020604051808303816000875af11580156107c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101ca9190610dc4565b6107f08383836109f6565b6107fc576107fc610a9c565b505050565b60005473ffffffffffffffffffffffffffffffffffffffff16331461030a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610574565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b610923837fa9059cbb000000000000000000000000000000000000000000000000000000008484610aa8565b6107fc576040517ffb7f507900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006323b872dd60e01b905060006040518281528560048201528460248201528360448201526020600060648360008b5af191505080156109b7573d80156109ad57600160005114601f3d111691506109b5565b6000873b1191505b505b806109ee576040517ff405907100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b600060e0829003610a3457610a2d847fd505accf000000000000000000000000000000000000000000000000000000008585610afb565b90506104c6565b610100829003610a6a57610a2d847f8fcbaf0c000000000000000000000000000000000000000000000000000000008585610afb565b6040517f6827585700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040513d6000823e3d81fd5b60006040518481528360048201528260248201526020600060448360008a5af1915050801561023b573d8015610aea57600160005114601f3d11169150610af2565b6000863b1191505b50949350505050565b6000816004016040518581528385600483013760206000838360008b5af192505050801561023b573d8015610aea57600160005114601f3d11169150610af2565b803573ffffffffffffffffffffffffffffffffffffffff81168114610b6057600080fd5b919050565b60008060408385031215610b7857600080fd5b610b8183610b3c565b946020939093013593505050565b600060208284031215610ba157600080fd5b5035919050565b60008083601f840112610bba57600080fd5b50813567ffffffffffffffff811115610bd257600080fd5b602083019150836020828501011115610bea57600080fd5b9250929050565b60008060008060608587031215610c0757600080fd5b610c1085610b3c565b935060208501359250604085013567ffffffffffffffff811115610c3357600080fd5b610c3f87828801610ba8565b95989497509550505050565b600060208284031215610c5d57600080fd5b6101ca82610b3c565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60006020808385031215610ca857600080fd5b823567ffffffffffffffff80821115610cc057600080fd5b818501915085601f830112610cd457600080fd5b813581811115610ce657610ce6610c66565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f83011681018181108582111715610d2957610d29610c66565b604052918252848201925083810185019188831115610d4757600080fd5b938501935b82851015610d6c57610d5d85610b3c565b84529385019392850192610d4c565b98975050505050505050565b600080600060408486031215610d8d57600080fd5b83359250602084013567ffffffffffffffff811115610dab57600080fd5b610db786828701610ba8565b9497909650939450505050565b600060208284031215610dd657600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b818103818111156101cd576101cd610e0c565b808201808211156101cd576101cd610e0c565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610e9257610e92610e0c565b506001019056fea26469706673582212203c4030d8e4fd032251f47f19b257241211e815812cd7d45d8d965652ddf2470e64736f6c634300081100330000000000000000000000001111111254eeb25477b68fb85ed929f73a960582000000000000000000000000111111111117dc0aa78b770fa6a738034120c302

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106100725760003560e01c806385eda2de1161005057806385eda2de146100e8578063af15d786146100fb578063ccee33d71461014757600080fd5b80630965d04b146100775780633ee5ef1f1461008c5780635886216f146100b2575b600080fd5b61008a610085366004610d52565b61015a565b005b61009f61009a366004610dbd565b61017d565b6040519081526020015b60405180910390f35b61009f6100c0366004610de7565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b61009f6100f6366004610dbd565b61024f565b6101227f000000000000000000000000a0844e046a5b7db55bb8dcdffbf0bbf9c6dc654681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100a9565b61009f610155366004610e09565b6102f1565b60408051600080825260208201909252610179918491849133916106db565b5050565b60003373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000a0844e046a5b7db55bb8dcdffbf0bbf9c6dc654616146101ee576040517fa454419900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5073ffffffffffffffffffffffffffffffffffffffff821660009081526020819052604090205461021f8282610ecf565b73ffffffffffffffffffffffffffffffffffffffff90931660009081526020819052604090208390555090919050565b60003373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000a0844e046a5b7db55bb8dcdffbf0bbf9c6dc654616146102c0576040517fa454419900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5073ffffffffffffffffffffffffffffffffffffffff821660009081526020819052604090205461021f8282610ee8565b60008573ffffffffffffffffffffffffffffffffffffffff81163014610343576040517f4ca8886700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000001111111254eeb25477b68fb85ed929f73a96058216146103b2576040517f4ca8886700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8284017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081810135918290037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff40810192918101919060018801908881037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3f01907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80810135906298968090610489907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0013582610ecf565b610493908d610efb565b61049d9190610f12565b97506000633b9aca006104bd63ffffffff60808a013560a01c168b610efb565b6104c79190610f12565b905060006104d6866040610ecf565b67ffffffffffffffff8111156104ee576104ee610e71565b6040519080825280601f01601f191660200182016040528015610518576020820181803683370190505b509050602081018688823786018381528a83016020909101527f01000000000000000000000000000000000000000000000000000000000000008c8c60008161056357610563610f4d565b9050013560f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19160361064b576105a3602089013589356108a3565b60006105af8587610f7c565b60601c90503660006105c4876014818b610fc4565b915091508273ffffffffffffffffffffffffffffffffffffffff16631944799f6105ef8d6020013590565b8685856040518563ffffffff1660e01b81526004016106119493929190610fee565b600060405180830381600087803b15801561062b57600080fd5b505af115801561063f573d6000803e3d6000fd5b5050505050505061065d565b61065d858560208b01358b35856106db565b81156106885761068873ffffffffffffffffffffffffffffffffffffffff841660808a013584610936565b6106c973ffffffffffffffffffffffffffffffffffffffff84167f0000000000000000000000001111111254eeb25477b68fb85ed929f73a9605828c61099d565b50505050505050505095945050505050565b843585016106e98185610a66565b61071f576040517f4b57606900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061072a82610b37565b905061074766038d7ea4c6800063ffffffff843560901c16610efb565b6107519085610ecf565b9350600061075e83610b70565b90506000845160a06107709190610ecf565b61077b906020610ecf565b90507f0000000000000000000000001111111254eeb25477b68fb85ed929f73a9605826107b1565b8281848460045afa50505050565b60408a013560208101818c0135818d013560601c308114156014831017156107fd577f5b34bf890000000000000000000000000000000000000000000000000000000060005260046000fd5b506040517fe5d7bde60000000000000000000000000000000000000000000000000000000081528c8e600483013785820160048583010152818382010193508a60048501528b60248501526040890135604485015286606485015287608485015289516108718160208d0160a488016107a3565b84810160a40152600081878f016004018183895af1610893573d6000823e3d81fd5b5050505050505050505050505050565b80156101795773ffffffffffffffffffffffffffffffffffffffff821660009081526020819052604090205481811015610909576040517fa7fd379200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff92909216600090815260208190526040902091039055565b610962837fa9059cbb000000000000000000000000000000000000000000000000000000008484610cb5565b610998576040517ffb7f507900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050565b6109c9837f095ea7b3000000000000000000000000000000000000000000000000000000008484610cb5565b610998576109fa837f095ea7b300000000000000000000000000000000000000000000000000000000846000610cb5565b1580610a2f5750610a2d837f095ea7b3000000000000000000000000000000000000000000000000000000008484610cb5565b155b15610998576040517f19be9a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60003681610a786101208601866110a8565b91509150600181830103803560001a6004820391506080811615610a9d576020820391505b813560e01c4211945060031c600f16841915610b2d578060180282035b80831115610b2b577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe88301927fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec013560601c833560e01c888203610b24574210159650610b2b9050565b5050610aba565b505b5050505092915050565b60003681610b496101208501856110a8565b91509150600181830103803560001a60801615610b6857602081033593505b505050919050565b600062ffffff823560b081901c82169160e082901c918491610b969160c81c1683610ecf565b9050814211610ba85750909392505050565b804210610bba57506000949350505050565b366000610bcb6101208801886110a8565b915091506001818301036000813560001a6078811660031c6007821692506080821615610bf9576020840393505b6004816018020184039350505086868260050284035b80851115610c95577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb8501803560f01c9990990198947ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd013560e81c428a1115610c8b57828a03428481038302908c03860201049b5050610c95565b9250889150610c0f565b5089610ca75780870342880383020499505b505050505050505050919050565b60006040518481528360048201528260248201526020600060448360008a5af19150508015610d01573d8015610cf757600160005114601f3d11169150610cff565b6000863b1191505b505b949350505050565b60008083601f840112610d1b57600080fd5b50813567ffffffffffffffff811115610d3357600080fd5b602083019150836020828501011115610d4b57600080fd5b9250929050565b60008060208385031215610d6557600080fd5b823567ffffffffffffffff811115610d7c57600080fd5b610d8885828601610d09565b90969095509350505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610db857600080fd5b919050565b60008060408385031215610dd057600080fd5b610dd983610d94565b946020939093013593505050565b600060208284031215610df957600080fd5b610e0282610d94565b9392505050565b600080600080600060808688031215610e2157600080fd5b610e2a86610d94565b94506020860135935060408601359250606086013567ffffffffffffffff811115610e5457600080fd5b610e6088828901610d09565b969995985093965092949392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610ee257610ee2610ea0565b92915050565b81810381811115610ee257610ee2610ea0565b8082028115828204841417610ee257610ee2610ea0565b600082610f48577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008135818116916014851015610fbc5780818660140360031b1b83161692505b505092915050565b60008085851115610fd457600080fd5b83861115610fe157600080fd5b5050820193919092039150565b73ffffffffffffffffffffffffffffffffffffffff8516815260006020606081840152855180606085015260005b818110156110385787810183015185820160800152820161101c565b506000608082860101527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0915081601f820116840190506080848203016040850152846080820152848660a0830137600060a0868301015260a082601f8701168201019250505095945050505050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126110dd57600080fd5b83018035915067ffffffffffffffff8211156110f857600080fd5b602001915036819003821315610d4b57600080fdfea26469706673582212209c7fa27ec20c16ed309e2009a17458ca2682f2e05f31b135d716c14e5c5730f464736f6c63430008110033

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

0000000000000000000000001111111254eeb25477b68fb85ed929f73a960582000000000000000000000000111111111117dc0aa78b770fa6a738034120c302

-----Decoded View---------------
Arg [0] : limitOrderProtocol (address): 0x1111111254EEB25477B68fb85Ed929f73A960582
Arg [1] : token (address): 0x111111111117dC0aa78b770fA6A738034120C302

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000001111111254eeb25477b68fb85ed929f73a960582
Arg [1] : 000000000000000000000000111111111117dc0aa78b770fa6a738034120c302


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
Chain Token Portfolio % Price Amount Value
ETH10.38%$0.00000136,527,895.8978$21.22
ETH7.14%$3,433.640.00425174$14.6
ETH5.82%$3,343.110.00355934$11.9
ETH4.81%$0.75746912.9942$9.84
ETH4.60%$2.483.7844$9.39
ETH4.19%$450.260.019$8.57
ETH4.15%$3,372.620.00251805$8.49
ETH4.12%$94,8830.00008881$8.43
ETH3.58%$0.7460269.7974$7.31
ETH3.36%$197.40.0348$6.88
ETH3.15%$0.022064291.4162$6.43
ETH2.82%$0.00021327,008.5807$5.76
ETH2.68%$5.391.0173$5.48
ETH2.54%$0.6177648.4016$5.19
ETH2.20%$0.9986164.498$4.49
ETH2.01%$14.112$4.11
ETH1.91%$3,294.130.00118541$3.9
ETH1.79%$0.0006086,029.7524$3.67
ETH1.77%$0.11825530.6776$3.63
ETH1.76%$0.9914223.6244$3.59
ETH1.74%$0.3975998.9572$3.56
ETH1.68%$0.020616166.4424$3.43
ETH1.63%<$0.0000011,436,533,059.6542$3.34
ETH1.44%$0.026702110.3115$2.95
ETH1.34%$0.9996712.7365$2.74
ETH1.31%<$0.000001186,738,158.7996$2.68
ETH1.28%$139.550.0188$2.62
ETH1.20%$0.00003178,679.7888$2.44
ETH1.14%$0.2451299.4754$2.32
ETH1.03%$3,6730.00057513$2.11
ETH0.81%$0.15540610.711$1.66
ETH0.64%$0.1990646.5293$1.3
ETH0.51%$0.0002893,609.526$1.04
ETH0.47%$0.00001855,051.983$0.9656
ETH0.45%$73.160.0125$0.9108
ETH0.43%$0.0968119.1109$0.882
ETH0.38%$3,267.920.00023824$0.7785
ETH0.37%$0.9079020.8388$0.7615
ETH0.37%$5.030.1512$0.7604
ETH0.36%$0.0005041,479.428$0.7457
ETH0.33%$1.140.5968$0.6796
ETH0.33%<$0.000001184,848,164.7694$0.6652
ETH0.32%$0.02679124.0563$0.6444
ETH0.28%$3,277.530.00017458$0.5721
ETH0.27%$1.160.4672$0.5419
ETH0.26%$0.1100924.7932$0.5276
ETH0.24%<$0.0000015,717,176.0041$0.4948
ETH0.23%$8.580.0536$0.46
ETH0.21%$0.01201536.4747$0.4382
ETH0.21%$0.0904744.8043$0.4346
ETH0.21%$14.890.0289$0.4298
ETH0.18%$3,535.280.00010248$0.3623
ETH0.17%$0.2546511.3656$0.3477
ETH0.17%$0.002353147.1384$0.3462
ETH0.16%$0.7062590.457$0.3227
ETH0.15%$39.660.00785654$0.3115
ETH0.15%$0.00964931.7236$0.3061
ETH0.14%$181.320.00154688$0.2804
ETH0.12%$0.00000546,438.6627$0.254
ETH0.12%$0.0269019.2658$0.2492
ETH0.11%$2.970.0748$0.2222
ETH0.11%$0.00362959.7655$0.2169
ETH0.10%<$0.000001767,961.7474$0.2052
ETH0.10%$0.00000730,052.9831$0.2028
ETH0.09%$0.1218861.4601$0.1779
ETH0.08%$0.000001179,937.0653$0.1696
ETH0.08%$0.4290430.3677$0.1577
ETH0.07%<$0.000001564,567.8395$0.149
ETH0.07%<$0.000001257,039,698.9939$0.1402
ETH0.07%<$0.0000017,546,638.2637$0.1355
ETH0.06%$0.00235856.2956$0.1327
ETH0.06%$0.0275854.8116$0.1327
ETH0.06%$0.0000216,199.6854$0.1321
ETH0.06%$0.001068121.2255$0.1295
ETH0.06%$0.0326283.5895$0.1171
ETH0.06%$0.0136178.5894$0.1169
ETH0.05%$0.00148174.1274$0.1097
ETH0.05%$0.0358153$0.1074
ETH0.05%$0.0114549.0829$0.104
ETH0.05%<$0.0000011,454,294.1807$0.1037
ARB0.54%$0.0005532,000$1.11
BASE0.20%<$0.00000111,111,111$0.4033
BASE0.19%$0.03128512.3$0.3848
POL<0.01%$0.4729710.0043$0.002034
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

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