S Price: $0.453413 (-10.85%)

Contract

0xd4c28318bf51e823bAE1C4FEC562b80C53E66467

Overview

S Balance

Sonic LogoSonic LogoSonic Logo0 S

S Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Sell Order Swap121331802025-03-06 21:24:062 days ago1741296246IN
0xd4c28318...C53E66467
5 S0.0110941455.01

Latest 2 internal transactions

Parent Transaction Hash Block From To
121331802025-03-06 21:24:062 days ago1741296246
0xd4c28318...C53E66467
5 S
48307072025-01-21 14:11:2047 days ago1737468680  Contract Creation0 S
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
UniversalPermit2Adapter

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 10000 runs

Other Settings:
paris EvmVersion
File 1 of 18 : UniversalPermit2Adapter.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;

import { SimulationAdapter } from "@call-simulation/SimulationAdapter.sol";
// solhint-disable no-unused-import
import { BasePermit2Adapter, IPermit2, Token } from "./base/BasePermit2Adapter.sol";
import {
  IArbitraryExecutionPermit2Adapter,
  ArbitraryExecutionPermit2Adapter
} from "./base/ArbitraryExecutionPermit2Adapter.sol";
import { ISwapPermit2Adapter, SwapPermit2Adapter } from "./base/SwapPermit2Adapter.sol";
// solhint-enable no-unused-import

/**
 * @title Universal Permit2 Adapter
 * @author Sam Bugs
 * @notice This contracts adds Permit2 capabilities to existing contracts by acting as a proxy
 * @dev It's important to note that this contract should never hold any funds outside of the scope of a transaction,
 *      nor should it be granted "regular" ERC20 token approvals. This contract is meant to be used as a proxy, so
 *      the only tokens approved/transferred through Permit2 should be entirely spent in the same transaction.
 *      Any unspent allowance or remaining tokens on the contract can be transferred by anyone, so please be careful!
 */
contract UniversalPermit2Adapter is SimulationAdapter, SwapPermit2Adapter, ArbitraryExecutionPermit2Adapter {
  constructor(IPermit2 _permit2) BasePermit2Adapter(_permit2) { }
}

File 2 of 18 : SimulationAdapter.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;

import { IERC165 } from "./interfaces/external/IERC165.sol";
import { ISimulationAdapter } from "./interfaces/ISimulationAdapter.sol";

/**
 * @title Simulation Adapter
 * @author Sam Bugs
 * @notice This contracts adds off-chain simulation capabilities to existing contracts. It works similarly to a
 *         multicall, but the state is not modified in each subcall.
 */
abstract contract SimulationAdapter is IERC165, ISimulationAdapter {
  /// @notice An error that contains a simulation's result
  error SimulatedCall(SimulationResult result);

  /// @inheritdoc IERC165
  function supportsInterface(bytes4 _interfaceId) public view virtual override returns (bool) {
    return _interfaceId == type(ISimulationAdapter).interfaceId || _interfaceId == type(IERC165).interfaceId;
  }

  /// @inheritdoc ISimulationAdapter
  function simulate(bytes[] calldata _calls) external payable returns (SimulationResult[] memory _results) {
    _results = new SimulationResult[](_calls.length);
    for (uint256 i = 0; i < _calls.length; i++) {
      _results[i] = _simulate(_calls[i]);
    }
    return _results;
  }

  /**
   * @notice Executes a simulation and returns the result
   * @param _call The call to simulate
   * @return _simulationResult The simulation's result
   */
  function _simulate(bytes calldata _call) internal returns (SimulationResult memory _simulationResult) {
    (bool _success, bytes memory _result) =
    // solhint-disable-next-line avoid-low-level-calls
     address(this).delegatecall(abi.encodeWithSelector(this.simulateAndRevert.selector, _call));
    require(!_success, "WTF? Should have failed!");
    // Move pointer to ignore selector
    // solhint-disable-next-line no-inline-assembly
    assembly {
      _result := add(_result, 0x04)
    }
    (_simulationResult) = abi.decode(_result, (SimulationResult));
  }

  /**
   * @notice Executes a call agains this contract and reverts with the result
   * @dev This is meant to be used internally, do not call!
   * @param _call The call to simulate
   */
  function simulateAndRevert(bytes calldata _call) external payable {
    uint256 _gasAtStart = gasleft();
    // solhint-disable-next-line avoid-low-level-calls
    (bool _success, bytes memory _result) = address(this).delegatecall(_call);
    uint256 _gasSpent = _gasAtStart - gasleft();
    revert SimulatedCall(SimulationResult({ success: _success, result: _result, gasSpent: _gasSpent }));
  }
}

File 3 of 18 : BasePermit2Adapter.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;

import { Address } from "@openzeppelin/contracts/utils/Address.sol";
import { IERC1271 } from "@openzeppelin/contracts/interfaces/IERC1271.sol";
import { IBasePermit2Adapter, IPermit2 } from "../interfaces/IBasePermit2Adapter.sol";
import { Token } from "../libraries/Token.sol";

/**
 * @title Base Permit2 Adapter
 * @author Sam Bugs
 * @notice The base contract for Permit2 adapters
 */
abstract contract BasePermit2Adapter is IBasePermit2Adapter, IERC1271 {
  using Address for address;

  /// @inheritdoc IBasePermit2Adapter
  address public constant NATIVE_TOKEN = Token.NATIVE_TOKEN;
  /// @inheritdoc IBasePermit2Adapter
  // solhint-disable-next-line var-name-mixedcase
  IPermit2 public immutable PERMIT2;

  bytes4 private constant MAGIC_WORD = IERC1271.isValidSignature.selector;

  constructor(IPermit2 _permit2) {
    PERMIT2 = _permit2;
  }

  // solhint-disable-next-line no-empty-blocks
  receive() external payable { }

  function isValidSignature(bytes32, bytes memory) external view returns (bytes4 magicValue) {
    // Note: both swap and arbitrary adapters support approving tokens for other addresses, for integrations to work. The
    //       thing is that sometimes, these third party contracts use Permit2 instead of using ERC20's transfer from.
    //       When that happens, the allowance target will need to be the Permit2 contract, and then Permit2 will call
    //       this function to make sure we authorize the  extraction of tokens. Since this contract is not meant to hold
    //       any funds outside of the scope of a swap or arbitrary execution, we'll allow it
    return msg.sender == address(PERMIT2) ? MAGIC_WORD : bytes4(0);
  }

  modifier checkDeadline(uint256 _deadline) {
    if (block.timestamp > _deadline) revert TransactionDeadlinePassed(block.timestamp, _deadline);
    _;
  }

  function _callContract(address _target, bytes calldata _data, uint256 _value) internal returns (bytes memory _result) {
    if (_target == address(PERMIT2)) revert InvalidContractCall();
    return _target.functionCallWithValue(_data, _value);
  }
}

File 4 of 18 : ArbitraryExecutionPermit2Adapter.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;

// solhint-disable-next-line no-unused-import
import { Permit2Transfers, IPermit2 } from "../libraries/Permit2Transfers.sol";
import { Token, IERC20 } from "../libraries/Token.sol";
import { IArbitraryExecutionPermit2Adapter } from "../interfaces/IArbitraryExecutionPermit2Adapter.sol";
import { BasePermit2Adapter } from "./BasePermit2Adapter.sol";

/**
 * @title Arbitrary Execution Permit2 Adapter
 * @author Sam Bugs
 * @notice This contracts adds Permit2 capabilities to existing contracts by acting as a proxy
 * @dev It's important to note that this contract should never hold any funds outside of the scope of a transaction,
 *      nor should it be granted "regular" ERC20 token approvals. This contract is meant to be used as a proxy, so
 *      the only tokens approved/transferred through Permit2 should be entirely spent in the same transaction.
 *      Any unspent allowance or remaining tokens on the contract can be transferred by anyone, so please be careful!
 */
abstract contract ArbitraryExecutionPermit2Adapter is BasePermit2Adapter, IArbitraryExecutionPermit2Adapter {
  using Permit2Transfers for IPermit2;
  using Token for address;
  using Token for IERC20;

  /// @inheritdoc IArbitraryExecutionPermit2Adapter
  function executeWithPermit(
    SinglePermit calldata _permit,
    AllowanceTarget[] calldata _allowanceTargets,
    ContractCall[] calldata _contractCalls,
    TransferOut[] calldata _transferOut,
    uint256 _deadline
  )
    external
    payable
    checkDeadline(_deadline)
    returns (bytes[] memory _executionResults, uint256[] memory _tokenBalances)
  {
    PERMIT2.takeFromCaller(_permit.token, _permit.amount, _permit.nonce, _deadline, _permit.signature);
    return _approveExecuteAndTransfer(_allowanceTargets, _contractCalls, _transferOut);
  }

  /// @inheritdoc IArbitraryExecutionPermit2Adapter
  function executeWithBatchPermit(
    BatchPermit calldata _batchPermit,
    AllowanceTarget[] calldata _allowanceTargets,
    ContractCall[] calldata _contractCalls,
    TransferOut[] calldata _transferOut,
    uint256 _deadline
  )
    external
    payable
    checkDeadline(_deadline)
    returns (bytes[] memory _executionResults, uint256[] memory _tokenBalances)
  {
    PERMIT2.batchTakeFromCaller(_batchPermit.tokens, _batchPermit.nonce, _deadline, _batchPermit.signature);
    return _approveExecuteAndTransfer(_allowanceTargets, _contractCalls, _transferOut);
  }

  function _approveExecuteAndTransfer(
    AllowanceTarget[] calldata _allowanceTargets,
    ContractCall[] calldata _contractCalls,
    TransferOut[] calldata _transferOut
  )
    internal
    returns (bytes[] memory _executionResults, uint256[] memory _tokenBalances)
  {
    // Approve targets
    for (uint256 i; i < _allowanceTargets.length;) {
      IERC20(_allowanceTargets[i].token).maxApprove(_allowanceTargets[i].allowanceTarget);
      unchecked {
        ++i;
      }
    }

    // Call contracts
    _executionResults = new bytes[](_contractCalls.length);
    for (uint256 i; i < _contractCalls.length;) {
      _executionResults[i] = _callContract(_contractCalls[i].target, _contractCalls[i].data, _contractCalls[i].value);
      unchecked {
        ++i;
      }
    }

    // Reset allowance to prevent attacks. Also, we are setting it to 1 instead of 0 for gas optimization
    for (uint256 i; i < _allowanceTargets.length;) {
      IERC20(_allowanceTargets[i].token).setAllowance(_allowanceTargets[i].allowanceTarget, 1);
      unchecked {
        ++i;
      }
    }

    // Distribute tokens
    _tokenBalances = new uint256[](_transferOut.length);
    for (uint256 i; i < _transferOut.length;) {
      _tokenBalances[i] = _transferOut[i].token.distributeTo(_transferOut[i].distribution);
      unchecked {
        ++i;
      }
    }
  }
}

File 5 of 18 : SwapPermit2Adapter.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;

// solhint-disable-next-line no-unused-import
import { Permit2Transfers, IPermit2 } from "../libraries/Permit2Transfers.sol";
import { Token } from "../libraries/Token.sol";
import { ISwapPermit2Adapter } from "../interfaces/ISwapPermit2Adapter.sol";
import { BasePermit2Adapter } from "./BasePermit2Adapter.sol";

/**
 * @title Swap Permit2 Adapter
 * @author Sam Bugs
 * @notice This contracts adds Permit2 capabilities to existing token swap contracts by acting as a proxy. It performs
 *         some extra checks to guarantee that the minimum amounts are respected
 * @dev It's important to note that this contract should never hold any funds outside of the scope of a transaction,
 *      nor should it be granted "regular" ERC20 token approvals. This contract is meant to be used as a proxy, so
 *      the only tokens approved/transferred through Permit2 should be entirely spent in the same transaction.
 *      Any unspent allowance or remaining tokens on the contract can be transferred by anyone, so please be careful!
 */
abstract contract SwapPermit2Adapter is BasePermit2Adapter, ISwapPermit2Adapter {
  using Permit2Transfers for IPermit2;
  using Token for address;

  /// @inheritdoc ISwapPermit2Adapter
  function sellOrderSwap(SellOrderSwapParams calldata _params)
    public
    payable
    checkDeadline(_params.deadline)
    returns (uint256 _amountIn, uint256 _amountOut)
  {
    // Take from caller
    PERMIT2.takeFromCaller(_params.tokenIn, _params.amountIn, _params.nonce, _params.deadline, _params.signature);

    // Max approve token in
    _params.tokenIn.maxApproveIfNecessary(_params.allowanceTarget);

    // Execute swap
    uint256 _value = _params.tokenIn == Token.NATIVE_TOKEN ? _params.amountIn : 0;
    _callContract(_params.swapper, _params.swapData, _value);

    // Distribute token out
    _amountOut = _params.tokenOut.distributeTo(_params.transferOut);

    // Check min amount
    if (_amountOut < _params.minAmountOut) revert ReceivedTooLittleTokenOut(_amountOut, _params.minAmountOut);

    // Reset allowance
    _params.tokenIn.setAllowanceIfNecessary(_params.allowanceTarget, 1);

    // Set amount in
    _amountIn = _params.amountIn;

    // Emit event
    emit Swapped({
      caller: msg.sender,
      swapType: SwapType.Sell,
      tokenIn: _params.tokenIn,
      tokenOut: _params.tokenOut,
      amountIn: _params.amountIn,
      amountOut: _amountOut,
      swapper: _params.swapper,
      misc: _params.misc
    });
  }

  /// @inheritdoc ISwapPermit2Adapter
  function buyOrderSwap(BuyOrderSwapParams calldata _params)
    public
    payable
    checkDeadline(_params.deadline)
    returns (uint256 _amountIn, uint256 _amountOut)
  {
    // Take from caller
    PERMIT2.takeFromCaller(_params.tokenIn, _params.maxAmountIn, _params.nonce, _params.deadline, _params.signature);

    // Max approve token in
    _params.tokenIn.maxApproveIfNecessary(_params.allowanceTarget);

    // Execute swap
    uint256 _value = _params.tokenIn == Token.NATIVE_TOKEN ? _params.maxAmountIn : 0;
    _callContract(_params.swapper, _params.swapData, _value);

    // Check balance for unspent tokens
    uint256 _unspentTokenIn = _params.tokenIn.balanceOnContract();

    // Distribute token out
    _amountOut = _params.tokenOut.distributeTo(_params.transferOut);

    // Check min amount
    if (_amountOut < _params.amountOut) revert ReceivedTooLittleTokenOut(_amountOut, _params.amountOut);

    // Send unspent to the set recipient
    _params.tokenIn.sendAmountTo(_unspentTokenIn, _params.unspentTokenInRecipient);

    // Reset allowance
    _params.tokenIn.setAllowanceIfNecessary(_params.allowanceTarget, 1);

    // Set amount in
    _amountIn = _params.maxAmountIn - _unspentTokenIn;

    // Emit event
    emit Swapped({
      caller: msg.sender,
      swapType: SwapType.Buy,
      tokenIn: _params.tokenIn,
      tokenOut: _params.tokenOut,
      amountIn: _amountIn,
      amountOut: _amountOut,
      swapper: _params.swapper,
      misc: _params.misc
    });
  }
}

File 6 of 18 : IERC165.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;

interface IERC165 {
  /**
   * @dev Returns true if this contract implements the interface defined by
   * `interfaceId`. See the corresponding
   * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
   * to learn more about how these ids are created.
   *
   * This function call must use less than 30 000 gas.
   */
  function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

File 7 of 18 : ISimulationAdapter.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;

interface ISimulationAdapter {
  /// @notice A simulation's result
  struct SimulationResult {
    bool success;
    bytes result;
    uint256 gasSpent;
  }

  /**
   * @notice Executes individual simulations against this contract but doesn't modify the state when doing so
   * @dev This function is meant to be used for off-chain simulation and should not be called on-chain
   * @param calls The calls to simulate
   * @return results Each simulation result
   */
  function simulate(bytes[] calldata calls) external payable returns (SimulationResult[] memory results);
}

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

pragma solidity ^0.8.19;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev The ETH balance of the account is not enough to perform the operation.
     */
    error AddressInsufficientBalance(address account);

    /**
     * @dev There's no code at `target` (it is not a contract).
     */
    error AddressEmptyCode(address target);

    /**
     * @dev A call to an address target failed. The target may have reverted.
     */
    error FailedInnerCall();

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

        (bool success, ) = recipient.call{value: amount}("");
        if (!success) {
            revert FailedInnerCall();
        }
    }

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

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with a
     * `customRevert` function as a fallback when `target` reverts.
     *
     * Requirements:
     *
     * - `customRevert` must be a reverting function.
     *
     * _Available since v5.0._
     */
    function functionCall(
        address target,
        bytes memory data,
        function() internal view customRevert
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, customRevert);
    }

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

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with a `customRevert` function as a fallback revert reason when `target` reverts.
     *
     * Requirements:
     *
     * - `customRevert` must be a reverting function.
     *
     * _Available since v5.0._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        function() internal view customRevert
    ) internal returns (bytes memory) {
        if (address(this).balance < value) {
            revert AddressInsufficientBalance(address(this));
        }
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, customRevert);
    }

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

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

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

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

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

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or with a default revert error.
     *
     * _Available since v5.0._
     */
    function verifyCallResult(bool success, bytes memory returndata) internal view returns (bytes memory) {
        return verifyCallResult(success, returndata, defaultRevert);
    }

    /**
     * @dev Same as {xref-Address-verifyCallResult-bool-bytes-}[`verifyCallResult`], but with a
     * `customRevert` function as a fallback when `success` is `false`.
     *
     * Requirements:
     *
     * - `customRevert` must be a reverting function.
     *
     * _Available since v5.0._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        function() internal view customRevert
    ) internal view returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, customRevert);
        }
    }

    /**
     * @dev Default reverting function when no `customRevert` is provided in a function call.
     */
    function defaultRevert() internal pure {
        revert FailedInnerCall();
    }

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

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

pragma solidity ^0.8.19;

/**
 * @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 10 of 18 : IBasePermit2Adapter.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;

import { IPermit2 } from "./external/IPermit2.sol";

/// @notice The interface all Permit2 adapters should implement
interface IBasePermit2Adapter {
  /// @notice Thrown when the user tries to execute an invalid contract call
  error InvalidContractCall();

  /**
   * @notice Thrown when a transaction deadline has passed
   * @param current The current time
   * @param deadline The set deadline
   */
  error TransactionDeadlinePassed(uint256 current, uint256 deadline);

  /**
   * @notice Returns the address that represents the native token
   * @dev This value is constant and cannot change
   * @return The address that represents the native token
   */
  function NATIVE_TOKEN() external view returns (address);

  /**
   * @notice Returns the address of the Permit2 contract
   * @dev This value is constant and cannot change
   * @return The address of the Permit2 contract
   */
  function PERMIT2() external view returns (IPermit2);
}

File 11 of 18 : Token.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;

import { SafeERC20, IERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { Address } from "@openzeppelin/contracts/utils/Address.sol";

/**
 * @title Token Library
 * @author Sam Bugs
 * @notice A small library that contains helpers for tokens (both ERC20 and native)
 */
library Token {
  using SafeERC20 for IERC20;
  using Address for address payable;
  using Address for address;

  /// @notice A specific target to distribute tokens to
  struct DistributionTarget {
    address recipient;
    uint256 shareBps;
  }

  address public constant NATIVE_TOKEN = address(0);

  /**
   * @notice Calculates the amount of token balance held by the contract
   * @param _token The token to check
   * @return _balance The current balance held by the contract
   */
  function balanceOnContract(address _token) internal view returns (uint256 _balance) {
    return _token == NATIVE_TOKEN ? address(this).balance : IERC20(_token).balanceOf(address(this));
  }

  /**
   * @notice Performs a max approval to the allowance target, for the given token
   * @param _token The token to approve
   * @param _allowanceTarget The spender that will be approved
   */
  function maxApprove(IERC20 _token, address _allowanceTarget) internal {
    setAllowance(_token, _allowanceTarget, type(uint256).max);
  }

  /**
   * @notice Performs an approval to the allowance target, for the given token and amount
   * @param _token The token to approve
   * @param _allowanceTarget The spender that will be approved
   * @param _amount The allowance to set
   */
  function setAllowance(IERC20 _token, address _allowanceTarget, uint256 _amount) internal {
    // This helper should handle cases like USDT. Thanks OZ!
    _token.forceApprove(_allowanceTarget, _amount);
  }

  /**
   * @notice Performs a max approval to the allowance target for the given token, as long as the token is not
   *         the native token, and the allowance target is not the zero address
   * @param _token The token to approve
   * @param _allowanceTarget The spender that will be approved
   */
  function maxApproveIfNecessary(address _token, address _allowanceTarget) internal {
    setAllowanceIfNecessary(_token, _allowanceTarget, type(uint256).max);
  }

  /**
   * @notice Performs an approval to the allowance target for the given token and amount, as long as the token is not
   *         the native token, and the allowance target is not the zero address
   * @param _token The token to approve
   * @param _allowanceTarget The spender that will be approved
   * @param _amount The allowance to set
   */
  function setAllowanceIfNecessary(address _token, address _allowanceTarget, uint256 _amount) internal {
    if (_token != NATIVE_TOKEN && _allowanceTarget != address(0)) {
      setAllowance(IERC20(_token), _allowanceTarget, _amount);
    }
  }

  /**
   * @notice Distributes the available amount of the given token according to the set distribution. All tokens
   *         will be distributed according to the configured shares. The last target will get sent all unassigned
   *         tokens
   * @param _token The token to distribute
   * @param _distribution How to distribute the available amount of the token. Must have at least one target
   */
  function distributeTo(
    address _token,
    DistributionTarget[] calldata _distribution
  )
    internal
    returns (uint256 _available)
  {
    _available = balanceOnContract(_token);
    uint256 _amountLeft = _available;

    // Distribute amounts
    for (uint256 i; i < _distribution.length - 1;) {
      uint256 _toSend = _available * _distribution[i].shareBps / 10_000;
      sendAmountTo(_token, _toSend, _distribution[i].recipient);
      _amountLeft -= _toSend;
      unchecked {
        ++i;
      }
    }

    // Send amount left to the last recipient
    sendAmountTo(_token, _amountLeft, _distribution[_distribution.length - 1].recipient);
  }

  /**
   * @notice Checks if the contract has any balance of the given token, and if it does,
   *         it sends it to the given recipient
   * @param _token The token to check
   * @param _recipient The recipient of the token balance
   * @return _balance The current balance held by the contract
   */
  function sendBalanceOnContractTo(address _token, address _recipient) internal returns (uint256 _balance) {
    _balance = balanceOnContract(_token);
    sendAmountTo(_token, _balance, _recipient);
  }

  /**
   * @notice Transfers the given amount of tokens from the contract to the recipient
   * @param _token The token to check
   * @param _amount The amount to send
   * @param _recipient The recipient
   */
  function sendAmountTo(address _token, uint256 _amount, address _recipient) internal {
    if (_amount > 0) {
      if (_recipient == address(0)) _recipient = msg.sender;
      if (_token == NATIVE_TOKEN) {
        payable(_recipient).sendValue(_amount);
      } else {
        IERC20(_token).safeTransfer(_recipient, _amount);
      }
    }
  }
}

File 12 of 18 : Permit2Transfers.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;

import { IPermit2 } from "../interfaces/external/IPermit2.sol";
import { Token } from "./Token.sol";

/**
 * @title Permit2 Transfers Library
 * @author Sam Bugs
 * @notice A small library to call Permit2's transfer from methods
 */
library Permit2Transfers {
  /**
   * @notice Executes a transfer from using Permit2
   * @param _permit2 The Permit2 contract
   * @param _token The token to transfer
   * @param _amount The amount to transfer
   * @param _nonce The owner's nonce
   * @param _deadline The signature's expiration deadline
   * @param _signature The signature that allows the transfer
   */
  function takeFromCaller(
    IPermit2 _permit2,
    address _token,
    uint256 _amount,
    uint256 _nonce,
    uint256 _deadline,
    bytes calldata _signature
  )
    internal
  {
    if (_signature.length > 0) {
      _permit2.permitTransferFrom(
        // The permit message.
        IPermit2.PermitTransferFrom({
          permitted: IPermit2.TokenPermissions({ token: _token, amount: _amount }),
          nonce: _nonce,
          deadline: _deadline
        }),
        // The transfer recipient and amount.
        IPermit2.SignatureTransferDetails({ to: address(this), requestedAmount: _amount }),
        // The owner of the tokens, which must also be
        // the signer of the message, otherwise this call
        // will fail.
        msg.sender,
        // The packed signature that was the result of signing
        // the EIP712 hash of `permit`.
        _signature
      );
    }
  }

  /**
   * @notice Executes a batch transfer from using Permit2
   * @param _permit2 The Permit2 contract
   * @param _tokens The amount of tokens to transfer
   * @param _nonce The owner's nonce
   * @param _deadline The signature's expiration deadline
   * @param _signature The signature that allows the transfer
   */
  function batchTakeFromCaller(
    IPermit2 _permit2,
    IPermit2.TokenPermissions[] calldata _tokens,
    uint256 _nonce,
    uint256 _deadline,
    bytes calldata _signature
  )
    internal
  {
    if (_tokens.length > 0) {
      _permit2.permitTransferFrom(
        // The permit message.
        IPermit2.PermitBatchTransferFrom({ permitted: _tokens, nonce: _nonce, deadline: _deadline }),
        // The transfer recipients and amounts.
        _buildTransferDetails(_tokens),
        // The owner of the tokens, which must also be
        // the signer of the message, otherwise this call
        // will fail.
        msg.sender,
        // The packed signature that was the result of signing
        // the EIP712 hash of `permit`.
        _signature
      );
    }
  }

  function _buildTransferDetails(IPermit2.TokenPermissions[] calldata _tokens)
    private
    view
    returns (IPermit2.SignatureTransferDetails[] memory _details)
  {
    _details = new IPermit2.SignatureTransferDetails[](_tokens.length);
    for (uint256 i; i < _details.length;) {
      _details[i] = IPermit2.SignatureTransferDetails({ to: address(this), requestedAmount: _tokens[i].amount });
      unchecked {
        ++i;
      }
    }
  }
}

File 13 of 18 : IArbitraryExecutionPermit2Adapter.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;

import { Token } from "../libraries/Token.sol";
import { IBasePermit2Adapter, IPermit2 } from "./IBasePermit2Adapter.sol";

interface IArbitraryExecutionPermit2Adapter is IBasePermit2Adapter {
  /// @notice Data necessary to execute a single permit transfer
  struct SinglePermit {
    address token;
    uint256 amount;
    uint256 nonce;
    bytes signature;
  }

  /// @notice Data necessary to execute a batch permit transfer
  struct BatchPermit {
    IPermit2.TokenPermissions[] tokens;
    uint256 nonce;
    bytes signature;
  }

  /// @notice Allowance target for a specific token
  struct AllowanceTarget {
    address token;
    address allowanceTarget;
  }

  /// @notice A specific contract call
  struct ContractCall {
    address target;
    bytes data;
    uint256 value;
  }

  /// @notice A token and how to distribute it
  struct TransferOut {
    address token;
    Token.DistributionTarget[] distribution;
  }

  /**
   * @notice Executes arbitrary calls by proxing to another contracts, but using Permit2 to transfer tokens from the
   *         caller
   * @param permit The permit data to use to transfer tokens from the user
   * @param allowanceTargets The contracts to approve before executing calls
   * @param contractCalls The calls to execute
   * @param transferOut The tokens to transfer out of our contract after all calls have been executed. Note that each
   *                    element of the array should handle different tokens
   * @param deadline The max time where this call can be executed
   * @return executionResults The results of each contract call
   * @return tokenBalances The balances held by the contract after contract calls were executed
   */
  function executeWithPermit(
    SinglePermit calldata permit,
    AllowanceTarget[] calldata allowanceTargets,
    ContractCall[] calldata contractCalls,
    TransferOut[] calldata transferOut,
    uint256 deadline
  )
    external
    payable
    returns (bytes[] memory executionResults, uint256[] memory tokenBalances);

  /**
   * @notice Executes arbitrary calls by proxing to another contracts, but using Permit2 to transfer tokens from the
   *         caller
   * @param batchPermit The permit data to use to batch transfer tokens from the user
   * @param allowanceTargets The contracts to approve before executing calls
   * @param contractCalls The calls to execute
   * @param transferOut The tokens to transfer out of our contract after all calls have been executed
   * @param deadline The max time where this call can be executed
   * @return executionResults The results of each contract call
   * @return tokenBalances The balances held by the contract after contract calls were executed
   */
  function executeWithBatchPermit(
    BatchPermit calldata batchPermit,
    AllowanceTarget[] calldata allowanceTargets,
    ContractCall[] calldata contractCalls,
    TransferOut[] calldata transferOut,
    uint256 deadline
  )
    external
    payable
    returns (bytes[] memory executionResults, uint256[] memory tokenBalances);
}

File 14 of 18 : ISwapPermit2Adapter.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;

import { Token } from "../libraries/Token.sol";
import { IBasePermit2Adapter } from "./IBasePermit2Adapter.sol";

interface ISwapPermit2Adapter is IBasePermit2Adapter {
  /**
   * @notice Thrown when the swap produced less token out than expected
   * @param received The amount of token out received
   * @param expected The amount of token out expected
   */
  error ReceivedTooLittleTokenOut(uint256 received, uint256 expected);

  /**
   * @notice Emitted when a swap ocurrs
   * @param caller The swap caller
   * @param swapType The swap type, 'buy' or 'sell'
   * @param tokenIn The token swapped
   * @param tokenOut The token received
   * @param amountIn The amount of token in swapped
   * @param amountOut The amount of token out received
   * @param swapper The aggregator address
   * @param misc Misc bytes
   */
  event Swapped(
    address caller,
    SwapType swapType,
    address tokenIn,
    address tokenOut,
    uint256 amountIn,
    uint256 amountOut,
    address swapper,
    bytes misc
  );

  /// @notice Swap params for a sell order
  struct SellOrderSwapParams {
    // Deadline
    uint256 deadline;
    // Take from caller
    address tokenIn;
    uint256 amountIn;
    uint256 nonce;
    bytes signature;
    // Swap approval
    address allowanceTarget;
    // Swap execution
    address swapper;
    bytes swapData;
    // Swap validation
    address tokenOut;
    uint256 minAmountOut;
    // Transfer token out
    Token.DistributionTarget[] transferOut;
    bytes misc;
  }

  // @notice Swap params for a buy order
  struct BuyOrderSwapParams {
    // Deadline
    uint256 deadline;
    // Take from caller
    address tokenIn;
    uint256 maxAmountIn;
    uint256 nonce;
    bytes signature;
    // Swap approval
    address allowanceTarget;
    // Swap execution
    address swapper;
    bytes swapData;
    // Swap validation
    address tokenOut;
    uint256 amountOut;
    // Transfer token out
    Token.DistributionTarget[] transferOut;
    // Transfer token in
    address unspentTokenInRecipient;
    bytes misc;
  }

  enum SwapType {
    Buy,
    Sell
  }

  /**
   * @notice Executes a sell order swap by proxing to another contract, but using Permit2 to transfer tokens from the
   * caller
   * @param params The swap's data, such as tokens, amounts, recipient, etc
   * @return amountIn The amount ot `token in` spent on the swap
   * @return amountOut The amount of `token out` produced by the proxied swap
   */
  function sellOrderSwap(SellOrderSwapParams calldata params)
    external
    payable
    returns (uint256 amountIn, uint256 amountOut);

  /**
   * @notice Executes a buy order swap by proxing to another contract, but using Permit2 to transfer tokens from the
   * caller
   * @param params The swap's data, such as tokens, amounts, recipient, etc
   * @return amountIn The amount ot `token in` spent on the swap
   * @return amountOut The amount of `token out` produced by the proxied swap
   */
  function buyOrderSwap(BuyOrderSwapParams calldata params)
    external
    payable
    returns (uint256 amountIn, uint256 amountOut);
}

File 15 of 18 : IPermit2.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;

// Minimal Permit2 interface, derived from
// https://github.com/Uniswap/permit2/blob/main/src/interfaces/ISignatureTransfer.sol
interface IPermit2 {
  struct TokenPermissions {
    address token;
    uint256 amount;
  }

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

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

  struct SignatureTransferDetails {
    address to;
    uint256 requestedAmount;
  }

  function DOMAIN_SEPARATOR() external view returns (bytes32);

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

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

File 16 of 18 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.19;

import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    /**
     * @dev An operation with an ERC20 token failed.
     */
    error SafeERC20FailedOperation(address token);

    /**
     * @dev Indicates a failed `decreaseAllowance` request.
     */
    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        forceApprove(token, spender, oldAllowance + value);
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
        unchecked {
            uint256 currentAllowance = token.allowance(address(this), spender);
            if (currentAllowance < requestedDecrease) {
                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
            }
            forceApprove(token, spender, currentAllowance - requestedDecrease);
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Compatible with tokens that require the approval to be set to
     * 0 before setting it to a non-zero value.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
     * Revert on invalid signature.
     */
    function safePermit(
        IERC20Permit token,
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        uint256 nonceBefore = token.nonces(owner);
        token.permit(owner, spender, value, deadline, v, r, s);
        uint256 nonceAfter = token.nonces(owner);
        if (nonceAfter != nonceBefore + 1) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data);
        if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
        // and not revert is the subcall reverts.

        (bool success, bytes memory returndata) = address(token).call(data);
        return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
    }
}

File 17 of 18 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.19;

/**
 * @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 18 of 18 : IERC20Permit.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.19;

/**
 * @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);
}

Settings
{
  "remappings": [
    "@prb/test/=lib/prb-test/src/",
    "forge-std/=lib/forge-std/src/",
    "src/=src/",
    "@openzeppelin/=lib/openzeppelin-contracts/",
    "@call-simulation/=lib/call-simulation/src/",
    "call-simulation/=lib/call-simulation/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "openzeppelin/=lib/openzeppelin-contracts/contracts/",
    "prb-test/=lib/prb-test/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 10000
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "none",
    "appendCBOR": false
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "viaIR": false,
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"contract IPermit2","name":"_permit2","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"InvalidContractCall","type":"error"},{"inputs":[{"internalType":"uint256","name":"received","type":"uint256"},{"internalType":"uint256","name":"expected","type":"uint256"}],"name":"ReceivedTooLittleTokenOut","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[{"components":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"result","type":"bytes"},{"internalType":"uint256","name":"gasSpent","type":"uint256"}],"internalType":"struct ISimulationAdapter.SimulationResult","name":"result","type":"tuple"}],"name":"SimulatedCall","type":"error"},{"inputs":[{"internalType":"uint256","name":"current","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"TransactionDeadlinePassed","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"enum ISwapPermit2Adapter.SwapType","name":"swapType","type":"uint8"},{"indexed":false,"internalType":"address","name":"tokenIn","type":"address"},{"indexed":false,"internalType":"address","name":"tokenOut","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOut","type":"uint256"},{"indexed":false,"internalType":"address","name":"swapper","type":"address"},{"indexed":false,"internalType":"bytes","name":"misc","type":"bytes"}],"name":"Swapped","type":"event"},{"inputs":[],"name":"NATIVE_TOKEN","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERMIT2","outputs":[{"internalType":"contract IPermit2","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"maxAmountIn","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"address","name":"allowanceTarget","type":"address"},{"internalType":"address","name":"swapper","type":"address"},{"internalType":"bytes","name":"swapData","type":"bytes"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"components":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"shareBps","type":"uint256"}],"internalType":"struct Token.DistributionTarget[]","name":"transferOut","type":"tuple[]"},{"internalType":"address","name":"unspentTokenInRecipient","type":"address"},{"internalType":"bytes","name":"misc","type":"bytes"}],"internalType":"struct ISwapPermit2Adapter.BuyOrderSwapParams","name":"_params","type":"tuple"}],"name":"buyOrderSwap","outputs":[{"internalType":"uint256","name":"_amountIn","type":"uint256"},{"internalType":"uint256","name":"_amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct IPermit2.TokenPermissions[]","name":"tokens","type":"tuple[]"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct IArbitraryExecutionPermit2Adapter.BatchPermit","name":"_batchPermit","type":"tuple"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"allowanceTarget","type":"address"}],"internalType":"struct IArbitraryExecutionPermit2Adapter.AllowanceTarget[]","name":"_allowanceTargets","type":"tuple[]"},{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"value","type":"uint256"}],"internalType":"struct IArbitraryExecutionPermit2Adapter.ContractCall[]","name":"_contractCalls","type":"tuple[]"},{"components":[{"internalType":"address","name":"token","type":"address"},{"components":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"shareBps","type":"uint256"}],"internalType":"struct Token.DistributionTarget[]","name":"distribution","type":"tuple[]"}],"internalType":"struct IArbitraryExecutionPermit2Adapter.TransferOut[]","name":"_transferOut","type":"tuple[]"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"executeWithBatchPermit","outputs":[{"internalType":"bytes[]","name":"_executionResults","type":"bytes[]"},{"internalType":"uint256[]","name":"_tokenBalances","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct IArbitraryExecutionPermit2Adapter.SinglePermit","name":"_permit","type":"tuple"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"allowanceTarget","type":"address"}],"internalType":"struct IArbitraryExecutionPermit2Adapter.AllowanceTarget[]","name":"_allowanceTargets","type":"tuple[]"},{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"value","type":"uint256"}],"internalType":"struct IArbitraryExecutionPermit2Adapter.ContractCall[]","name":"_contractCalls","type":"tuple[]"},{"components":[{"internalType":"address","name":"token","type":"address"},{"components":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"shareBps","type":"uint256"}],"internalType":"struct Token.DistributionTarget[]","name":"distribution","type":"tuple[]"}],"internalType":"struct IArbitraryExecutionPermit2Adapter.TransferOut[]","name":"_transferOut","type":"tuple[]"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"executeWithPermit","outputs":[{"internalType":"bytes[]","name":"_executionResults","type":"bytes[]"},{"internalType":"uint256[]","name":"_tokenBalances","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"isValidSignature","outputs":[{"internalType":"bytes4","name":"magicValue","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"address","name":"allowanceTarget","type":"address"},{"internalType":"address","name":"swapper","type":"address"},{"internalType":"bytes","name":"swapData","type":"bytes"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"components":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"shareBps","type":"uint256"}],"internalType":"struct Token.DistributionTarget[]","name":"transferOut","type":"tuple[]"},{"internalType":"bytes","name":"misc","type":"bytes"}],"internalType":"struct ISwapPermit2Adapter.SellOrderSwapParams","name":"_params","type":"tuple"}],"name":"sellOrderSwap","outputs":[{"internalType":"uint256","name":"_amountIn","type":"uint256"},{"internalType":"uint256","name":"_amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"_calls","type":"bytes[]"}],"name":"simulate","outputs":[{"components":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"result","type":"bytes"},{"internalType":"uint256","name":"gasSpent","type":"uint256"}],"internalType":"struct ISimulationAdapter.SimulationResult[]","name":"_results","type":"tuple[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"_call","type":"bytes"}],"name":"simulateAndRevert","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

60a06040523480156200001157600080fd5b506040516200273838038062002738833981016040819052620000349162000046565b6001600160a01b031660805262000078565b6000602082840312156200005957600080fd5b81516001600160a01b03811681146200007157600080fd5b9392505050565b608051612688620000b0600039600081816101ef015281816102f2015281816103c80152818161087a015261107901526126886000f3fe6080604052600436106100b55760003560e01c80634321431a11610069578063bcbef2061161004e578063bcbef20614610211578063ee4cfaf714610226578063ee8117211461023957600080fd5b80634321431a146101b55780636afdd850146101dd57600080fd5b80632c8aaabe1161009a5780632c8aaabe1461014757806331f7d964146101685780633ed242b41461019557600080fd5b806301ffc9a7146100c15780631626ba7e146100f657600080fd5b366100bc57005b600080fd5b3480156100cd57600080fd5b506100e16100dc366004611992565b61024c565b60405190151581526020015b60405180910390f35b34801561010257600080fd5b50610116610111366004611ac1565b6102e5565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681526020016100ed565b61015a610155366004611bdc565b610347565b6040516100ed929190611d18565b34801561017457600080fd5b5061017d600081565b6040516001600160a01b0390911681526020016100ed565b6101a86101a3366004611dd1565b610413565b6040516100ed9190611e48565b6101c86101c3366004611ec8565b6104f6565b604080519283526020830191909152016100ed565b3480156101e957600080fd5b5061017d7f000000000000000000000000000000000000000000000000000000000000000081565b61022461021f366004611f04565b610740565b005b61015a610234366004611f76565b610806565b6101c8610247366004611fbe565b6108a5565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f3ed242b40000000000000000000000000000000000000000000000000000000014806102df57507fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000145b92915050565b6000336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461031e576000610340565b7f1626ba7e000000000000000000000000000000000000000000000000000000005b9392505050565b6060808280421115610393576040517f25f14a28000000000000000000000000000000000000000000000000000000008152426004820152602481018290526044015b60405180910390fd5b6103f36103a360208d018d612016565b8c602001358d60400135878f80606001906103be9190612031565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016959493929190610ae4565b6104018a8a8a8a8a8a610bad565b92509250509850989650505050505050565b60608167ffffffffffffffff81111561042e5761042e6119d4565b60405190808252806020026020018201604052801561048557816020015b610472604051806060016040528060001515815260200160608152602001600081525090565b81526020019060019003908161044c5790505b50905060005b828110156104ef576104bf8484838181106104a8576104a8612096565b90506020028101906104ba9190612031565b610e9f565b8282815181106104d1576104d1612096565b602002602001018190525080806104e7906120f4565b91505061048b565b5092915050565b60008082354281101561053e576040517f25f14a280000000000000000000000000000000000000000000000000000000081524260048201526024810182905260440161038a565b61056a6105516040860160208701612016565b6040860135606087013587356103be60808a018a612031565b61059c61057d60c0860160a08701612016565b61058d6040870160208801612016565b6001600160a01b031690611046565b6000806105af6040870160208801612016565b6001600160a01b0316146105c45760006105ca565b84604001355b90506105f26105df60e0870160c08801612016565b6105ec60e0880188612031565b84611075565b5061062661060461014087018761212c565b61061661012089016101008a01612016565b6001600160a01b03169190611138565b9250846101200135831015610675576040517f763dfca000000000000000000000000000000000000000000000000000000000815260048101849052610120860135602482015260440161038a565b6106aa61068860c0870160a08801612016565b600161069a6040890160208a01612016565b6001600160a01b03169190611204565b60408501803594507ff186b619e99ec011dd2df76f232917ce8326af9997ad34223335e401e95536f29033906001906106e69060208a01612016565b6106f86101208a016101008b01612016565b60408a01358861070e60e08d0160c08e01612016565b61071c6101608e018e612031565b604051610731999897969594939291906121dd565b60405180910390a15050915091565b60005a9050600080306001600160a01b03168585604051610762929190612274565b600060405180830381855af49150503d806000811461079d576040519150601f19603f3d011682016040523d82523d6000602084013e6107a2565b606091505b509150915060005a6107b49085612284565b905060405180606001604052808415158152602001838152602001828152506040517f493703af00000000000000000000000000000000000000000000000000000000815260040161038a9190612297565b606080828042111561084d576040517f25f14a280000000000000000000000000000000000000000000000000000000081524260048201526024810182905260440161038a565b6103f361085a8c8061212c565b8d60200135878f80604001906108709190612031565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016959493929190611239565b6000808235428110156108ed576040517f25f14a280000000000000000000000000000000000000000000000000000000081524260048201526024810182905260440161038a565b6109006105516040860160208701612016565b61091361057d60c0860160a08701612016565b6000806109266040870160208801612016565b6001600160a01b03161461093b576000610941565b84604001355b90506109566105df60e0870160c08801612016565b50600061097a61096c6040880160208901612016565b6001600160a01b03166112e8565b905061099f61098d61014088018861212c565b6106166101208a016101008b01612016565b93508561012001358410156109ee576040517f763dfca000000000000000000000000000000000000000000000000000000000815260048101859052610120870135602482015260440161038a565b610a2481610a0461018089016101608a01612016565b610a1460408a0160208b01612016565b6001600160a01b03169190611386565b610a49610a3760c0880160a08901612016565b600161069a60408a0160208b01612016565b610a57816040880135612284565b94507ff186b619e99ec011dd2df76f232917ce8326af9997ad34223335e401e95536f2336000610a8d60408a0160208b01612016565b610a9f6101208b016101008c01612016565b8989610ab160e08e0160c08f01612016565b610abf6101808f018f612031565b604051610ad4999897969594939291906121dd565b60405180910390a1505050915091565b8015610ba4576040805160a0810182526001600160a01b038881166060830190815260808301899052825260208083018890528284018790528351808501855230815290810189905292517f30f28b7a000000000000000000000000000000000000000000000000000000008152908a16926330f28b7a92610b71929091903390889088906004016122aa565b600060405180830381600087803b158015610b8b57600080fd5b505af1158015610b9f573d6000803e3d6000fd5b505050505b50505050505050565b60608060005b87811015610c2757610c1f898983818110610bd057610bd0612096565b9050604002016020016020810190610be89190612016565b8a8a84818110610bfa57610bfa612096565b610c109260206040909202019081019150612016565b6001600160a01b0316906113d2565b600101610bb3565b508467ffffffffffffffff811115610c4157610c416119d4565b604051908082528060200260200182016040528015610c7457816020015b6060815260200190600190039081610c5f5790505b50915060005b85811015610d3b57610d16878783818110610c9757610c97612096565b9050602002810190610ca9919061232f565b610cb7906020810190612016565b888884818110610cc957610cc9612096565b9050602002810190610cdb919061232f565b610ce9906020810190612031565b8a8a86818110610cfb57610cfb612096565b9050602002810190610d0d919061232f565b60400135611075565b838281518110610d2857610d28612096565b6020908102919091010152600101610c7a565b5060005b87811015610db657610dae898983818110610d5c57610d5c612096565b9050604002016020016020810190610d749190612016565b60018b8b85818110610d8857610d88612096565b610d9e9260206040909202019081019150612016565b6001600160a01b031691906113f9565b600101610d3f565b508267ffffffffffffffff811115610dd057610dd06119d4565b604051908082528060200260200182016040528015610df9578160200160208202803683370190505b50905060005b83811015610e9357610e6e858583818110610e1c57610e1c612096565b9050602002810190610e2e919061236d565b610e3c90602081019061212c565b878785818110610e4e57610e4e612096565b9050602002810190610e60919061236d565b610616906020810190612016565b828281518110610e8057610e80612096565b6020908102919091010152600101610dff565b50965096945050505050565b610ec5604051806060016040528060001515815260200160608152602001600081525090565b600080306001600160a01b031663bcbef20660e01b8686604051602401610eed9291906123a1565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529051610f7691906123b5565b600060405180830381855af49150503d8060008114610fb1576040519150601f19603f3d011682016040523d82523d6000602084013e610fb6565b606091505b50915091508115611023576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f5754463f2053686f756c642068617665206661696c6564210000000000000000604482015260640161038a565b6004810190508080602001905181019061103d91906123d7565b95945050505050565b61107182827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff611204565b5050565b60607f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316856001600160a01b0316036110e2576040517fe0d7940800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61112d84848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050506001600160a01b0388169190508461140d565b90505b949350505050565b6000611143846112e8565b90508060005b611154600185612284565b8110156111da57600061271086868481811061117257611172612096565b9050604002016020013585611187919061249c565b61119191906124b3565b90506111c587828888868181106111aa576111aa612096565b6111c09260206040909202019081019150612016565b611386565b6111cf8184612284565b925050600101611149565b506111fc858286866111ed600182612284565b8181106111aa576111aa612096565b509392505050565b6001600160a01b0383161580159061122457506001600160a01b03821615155b15611234576112348383836113f9565b505050565b8415610ba457866001600160a01b031663edd9444b60405180606001604052808989808060200260200160405190810160405280939291908181526020016000905b828210156112a757611298604083028601368190038101906124ee565b8152602001906001019061127b565b50505050508152602001878152602001868152506112c5898961141d565b3386866040518663ffffffff1660e01b8152600401610b7195949392919061259d565b60006001600160a01b0382161561137f576040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa158015611356573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061137a9190612654565b6102df565b4792915050565b8115611234576001600160a01b03811661139d5750335b6001600160a01b0383166113be576112346001600160a01b038216836114ea565b6112346001600160a01b03841682846115b3565b61107182827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b6112346001600160a01b0384168383611627565b60606111308484846116eb61171d565b60608167ffffffffffffffff811115611438576114386119d4565b60405190808252806020026020018201604052801561147d57816020015b60408051808201909152600080825260208201528152602001906001900390816114565790505b50905060005b81518110156104ef576040518060400160405280306001600160a01b031681526020018585848181106114b8576114b8612096565b905060400201602001358152508282815181106114d7576114d7612096565b6020908102919091010152600101611483565b80471015611526576040517fcd78605900000000000000000000000000000000000000000000000000000000815230600482015260240161038a565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114611573576040519150601f19603f3d011682016040523d82523d6000602084013e611578565b606091505b5050905080611234576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b0383811660248301526044820183905261123491859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506117d5565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b3000000000000000000000000000000000000000000000000000000001790526116a68482611851565b6116e5576040516001600160a01b038481166024830152600060448301526116db91869182169063095ea7b3906064016115e0565b6116e584826117d5565b50505050565b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608247101561175b576040517fcd78605900000000000000000000000000000000000000000000000000000000815230600482015260240161038a565b600080866001600160a01b0316858760405161177791906123b5565b60006040518083038185875af1925050503d80600081146117b4576040519150601f19603f3d011682016040523d82523d6000602084013e6117b9565b606091505b50915091506117ca878383876118f4565b979650505050505050565b60006117ea6001600160a01b03841683611965565b9050805160001415801561180f57508080602001905181019061180d919061266d565b155b15611234576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b038416600482015260240161038a565b6000806000846001600160a01b03168460405161186e91906123b5565b6000604051808303816000865af19150503d80600081146118ab576040519150601f19603f3d011682016040523d82523d6000602084013e6118b0565b606091505b50915091508180156118da5750805115806118da5750808060200190518101906118da919061266d565b801561103d5750505050506001600160a01b03163b151590565b6060831561195b57825160000361195457846001600160a01b03163b600003611954576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b038616600482015260240161038a565b5081611130565b6111308383611976565b6060610340838360006116eb61171d565b8151156119865781518083602001fd5b6116eb8163ffffffff16565b6000602082840312156119a457600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461034057600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516060810167ffffffffffffffff81118282101715611a2657611a266119d4565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611a7357611a736119d4565b604052919050565b600067ffffffffffffffff821115611a9557611a956119d4565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60008060408385031215611ad457600080fd5b82359150602083013567ffffffffffffffff811115611af257600080fd5b8301601f81018513611b0357600080fd5b8035611b16611b1182611a7b565b611a2c565b818152866020838501011115611b2b57600080fd5b816020840160208301376000602083830101528093505050509250929050565b60008083601f840112611b5d57600080fd5b50813567ffffffffffffffff811115611b7557600080fd5b6020830191508360208260061b8501011115611b9057600080fd5b9250929050565b60008083601f840112611ba957600080fd5b50813567ffffffffffffffff811115611bc157600080fd5b6020830191508360208260051b8501011115611b9057600080fd5b60008060008060008060008060a0898b031215611bf857600080fd5b883567ffffffffffffffff80821115611c1057600080fd5b908a01906080828d031215611c2457600080fd5b90985060208a01359080821115611c3a57600080fd5b611c468c838d01611b4b565b909950975060408b0135915080821115611c5f57600080fd5b611c6b8c838d01611b97565b909750955060608b0135915080821115611c8457600080fd5b50611c918b828c01611b97565b999c989b50969995989497949560800135949350505050565b60005b83811015611cc5578181015183820152602001611cad565b50506000910152565b60008151808452611ce6816020860160208601611caa565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000604082016040835280855180835260608501915060608160051b8601019250602080880160005b83811015611d8d577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0888703018552611d7b868351611cce565b95509382019390820190600101611d41565b50508584038187015286518085528782019482019350915060005b82811015611dc457845184529381019392810192600101611da8565b5091979650505050505050565b60008060208385031215611de457600080fd5b823567ffffffffffffffff811115611dfb57600080fd5b611e0785828601611b97565b90969095509350505050565b8051151582526000602082015160606020850152611e346060850182611cce565b604093840151949093019390935250919050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015611ebb577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452611ea9858351611e13565b94509285019290850190600101611e6f565b5092979650505050505050565b600060208284031215611eda57600080fd5b813567ffffffffffffffff811115611ef157600080fd5b8201610180818503121561034057600080fd5b60008060208385031215611f1757600080fd5b823567ffffffffffffffff80821115611f2f57600080fd5b818501915085601f830112611f4357600080fd5b813581811115611f5257600080fd5b866020828501011115611f6457600080fd5b60209290920196919550909350505050565b60008060008060008060008060a0898b031215611f9257600080fd5b883567ffffffffffffffff80821115611faa57600080fd5b908a01906060828d031215611c2457600080fd5b600060208284031215611fd057600080fd5b813567ffffffffffffffff811115611fe757600080fd5b82016101a0818503121561034057600080fd5b80356001600160a01b038116811461201157600080fd5b919050565b60006020828403121561202857600080fd5b61034082611ffa565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261206657600080fd5b83018035915067ffffffffffffffff82111561208157600080fd5b602001915036819003821315611b9057600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612125576121256120c5565b5060010190565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261216157600080fd5b83018035915067ffffffffffffffff82111561217c57600080fd5b6020019150600681901b3603821315611b9057600080fd5b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b60006101006001600160a01b03808d16845260028c10612226577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8b6020850152808b166040850152808a1660608501528860808501528760a085015280871660c0850152508060e08401526122648184018587612194565b9c9b505050505050505050505050565b8183823760009101908152919050565b818103818111156102df576102df6120c5565b6020815260006103406020830184611e13565b60006101006122cd83895180516001600160a01b03168252602090810151910152565b6020880151604084015260408801516060840152612301608084018880516001600160a01b03168252602090810151910152565b6001600160a01b03861660c08401528060e08401526123238184018587612194565b98975050505050505050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa183360301811261236357600080fd5b9190910192915050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc183360301811261236357600080fd5b602081526000611130602083018486612194565b60008251612363818460208701611caa565b8051801515811461201157600080fd5b600060208083850312156123ea57600080fd5b825167ffffffffffffffff8082111561240257600080fd5b908401906060828703121561241657600080fd5b61241e611a03565b612427836123c7565b8152838301518281111561243a57600080fd5b83019150601f8201871361244d57600080fd5b815161245b611b1182611a7b565b818152888683860101111561246f57600080fd5b61247e82878301888701611caa565b80868401525050604083015160408201528094505050505092915050565b80820281158282048414176102df576102df6120c5565b6000826124e9577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60006040828403121561250057600080fd5b6040516040810181811067ffffffffffffffff82111715612523576125236119d4565b60405261252f83611ffa565b8152602083013560208201528091505092915050565b600081518084526020808501945080840160005b838110156125925761257f87835180516001600160a01b03168252602090810151910152565b6040969096019590820190600101612559565b509495945050505050565b60808152600060e082018751606060808501528181518084526101008601915060209350838301925060005b81811015612602576125ef83855180516001600160a01b03168252602090810151910152565b92840192604092909201916001016125c9565b5050828a015160a086015260408a015160c086015284810383860152612628818a612545565b9250505061264160408401876001600160a01b03169052565b8281036060840152612323818587612194565b60006020828403121561266657600080fd5b5051919050565b60006020828403121561267f57600080fd5b610340826123c756000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3

Deployed Bytecode

0x6080604052600436106100b55760003560e01c80634321431a11610069578063bcbef2061161004e578063bcbef20614610211578063ee4cfaf714610226578063ee8117211461023957600080fd5b80634321431a146101b55780636afdd850146101dd57600080fd5b80632c8aaabe1161009a5780632c8aaabe1461014757806331f7d964146101685780633ed242b41461019557600080fd5b806301ffc9a7146100c15780631626ba7e146100f657600080fd5b366100bc57005b600080fd5b3480156100cd57600080fd5b506100e16100dc366004611992565b61024c565b60405190151581526020015b60405180910390f35b34801561010257600080fd5b50610116610111366004611ac1565b6102e5565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681526020016100ed565b61015a610155366004611bdc565b610347565b6040516100ed929190611d18565b34801561017457600080fd5b5061017d600081565b6040516001600160a01b0390911681526020016100ed565b6101a86101a3366004611dd1565b610413565b6040516100ed9190611e48565b6101c86101c3366004611ec8565b6104f6565b604080519283526020830191909152016100ed565b3480156101e957600080fd5b5061017d7f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba381565b61022461021f366004611f04565b610740565b005b61015a610234366004611f76565b610806565b6101c8610247366004611fbe565b6108a5565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f3ed242b40000000000000000000000000000000000000000000000000000000014806102df57507fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000145b92915050565b6000336001600160a01b037f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3161461031e576000610340565b7f1626ba7e000000000000000000000000000000000000000000000000000000005b9392505050565b6060808280421115610393576040517f25f14a28000000000000000000000000000000000000000000000000000000008152426004820152602481018290526044015b60405180910390fd5b6103f36103a360208d018d612016565b8c602001358d60400135878f80606001906103be9190612031565b6001600160a01b037f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba316959493929190610ae4565b6104018a8a8a8a8a8a610bad565b92509250509850989650505050505050565b60608167ffffffffffffffff81111561042e5761042e6119d4565b60405190808252806020026020018201604052801561048557816020015b610472604051806060016040528060001515815260200160608152602001600081525090565b81526020019060019003908161044c5790505b50905060005b828110156104ef576104bf8484838181106104a8576104a8612096565b90506020028101906104ba9190612031565b610e9f565b8282815181106104d1576104d1612096565b602002602001018190525080806104e7906120f4565b91505061048b565b5092915050565b60008082354281101561053e576040517f25f14a280000000000000000000000000000000000000000000000000000000081524260048201526024810182905260440161038a565b61056a6105516040860160208701612016565b6040860135606087013587356103be60808a018a612031565b61059c61057d60c0860160a08701612016565b61058d6040870160208801612016565b6001600160a01b031690611046565b6000806105af6040870160208801612016565b6001600160a01b0316146105c45760006105ca565b84604001355b90506105f26105df60e0870160c08801612016565b6105ec60e0880188612031565b84611075565b5061062661060461014087018761212c565b61061661012089016101008a01612016565b6001600160a01b03169190611138565b9250846101200135831015610675576040517f763dfca000000000000000000000000000000000000000000000000000000000815260048101849052610120860135602482015260440161038a565b6106aa61068860c0870160a08801612016565b600161069a6040890160208a01612016565b6001600160a01b03169190611204565b60408501803594507ff186b619e99ec011dd2df76f232917ce8326af9997ad34223335e401e95536f29033906001906106e69060208a01612016565b6106f86101208a016101008b01612016565b60408a01358861070e60e08d0160c08e01612016565b61071c6101608e018e612031565b604051610731999897969594939291906121dd565b60405180910390a15050915091565b60005a9050600080306001600160a01b03168585604051610762929190612274565b600060405180830381855af49150503d806000811461079d576040519150601f19603f3d011682016040523d82523d6000602084013e6107a2565b606091505b509150915060005a6107b49085612284565b905060405180606001604052808415158152602001838152602001828152506040517f493703af00000000000000000000000000000000000000000000000000000000815260040161038a9190612297565b606080828042111561084d576040517f25f14a280000000000000000000000000000000000000000000000000000000081524260048201526024810182905260440161038a565b6103f361085a8c8061212c565b8d60200135878f80604001906108709190612031565b6001600160a01b037f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba316959493929190611239565b6000808235428110156108ed576040517f25f14a280000000000000000000000000000000000000000000000000000000081524260048201526024810182905260440161038a565b6109006105516040860160208701612016565b61091361057d60c0860160a08701612016565b6000806109266040870160208801612016565b6001600160a01b03161461093b576000610941565b84604001355b90506109566105df60e0870160c08801612016565b50600061097a61096c6040880160208901612016565b6001600160a01b03166112e8565b905061099f61098d61014088018861212c565b6106166101208a016101008b01612016565b93508561012001358410156109ee576040517f763dfca000000000000000000000000000000000000000000000000000000000815260048101859052610120870135602482015260440161038a565b610a2481610a0461018089016101608a01612016565b610a1460408a0160208b01612016565b6001600160a01b03169190611386565b610a49610a3760c0880160a08901612016565b600161069a60408a0160208b01612016565b610a57816040880135612284565b94507ff186b619e99ec011dd2df76f232917ce8326af9997ad34223335e401e95536f2336000610a8d60408a0160208b01612016565b610a9f6101208b016101008c01612016565b8989610ab160e08e0160c08f01612016565b610abf6101808f018f612031565b604051610ad4999897969594939291906121dd565b60405180910390a1505050915091565b8015610ba4576040805160a0810182526001600160a01b038881166060830190815260808301899052825260208083018890528284018790528351808501855230815290810189905292517f30f28b7a000000000000000000000000000000000000000000000000000000008152908a16926330f28b7a92610b71929091903390889088906004016122aa565b600060405180830381600087803b158015610b8b57600080fd5b505af1158015610b9f573d6000803e3d6000fd5b505050505b50505050505050565b60608060005b87811015610c2757610c1f898983818110610bd057610bd0612096565b9050604002016020016020810190610be89190612016565b8a8a84818110610bfa57610bfa612096565b610c109260206040909202019081019150612016565b6001600160a01b0316906113d2565b600101610bb3565b508467ffffffffffffffff811115610c4157610c416119d4565b604051908082528060200260200182016040528015610c7457816020015b6060815260200190600190039081610c5f5790505b50915060005b85811015610d3b57610d16878783818110610c9757610c97612096565b9050602002810190610ca9919061232f565b610cb7906020810190612016565b888884818110610cc957610cc9612096565b9050602002810190610cdb919061232f565b610ce9906020810190612031565b8a8a86818110610cfb57610cfb612096565b9050602002810190610d0d919061232f565b60400135611075565b838281518110610d2857610d28612096565b6020908102919091010152600101610c7a565b5060005b87811015610db657610dae898983818110610d5c57610d5c612096565b9050604002016020016020810190610d749190612016565b60018b8b85818110610d8857610d88612096565b610d9e9260206040909202019081019150612016565b6001600160a01b031691906113f9565b600101610d3f565b508267ffffffffffffffff811115610dd057610dd06119d4565b604051908082528060200260200182016040528015610df9578160200160208202803683370190505b50905060005b83811015610e9357610e6e858583818110610e1c57610e1c612096565b9050602002810190610e2e919061236d565b610e3c90602081019061212c565b878785818110610e4e57610e4e612096565b9050602002810190610e60919061236d565b610616906020810190612016565b828281518110610e8057610e80612096565b6020908102919091010152600101610dff565b50965096945050505050565b610ec5604051806060016040528060001515815260200160608152602001600081525090565b600080306001600160a01b031663bcbef20660e01b8686604051602401610eed9291906123a1565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529051610f7691906123b5565b600060405180830381855af49150503d8060008114610fb1576040519150601f19603f3d011682016040523d82523d6000602084013e610fb6565b606091505b50915091508115611023576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f5754463f2053686f756c642068617665206661696c6564210000000000000000604482015260640161038a565b6004810190508080602001905181019061103d91906123d7565b95945050505050565b61107182827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff611204565b5050565b60607f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba36001600160a01b0316856001600160a01b0316036110e2576040517fe0d7940800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61112d84848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050506001600160a01b0388169190508461140d565b90505b949350505050565b6000611143846112e8565b90508060005b611154600185612284565b8110156111da57600061271086868481811061117257611172612096565b9050604002016020013585611187919061249c565b61119191906124b3565b90506111c587828888868181106111aa576111aa612096565b6111c09260206040909202019081019150612016565b611386565b6111cf8184612284565b925050600101611149565b506111fc858286866111ed600182612284565b8181106111aa576111aa612096565b509392505050565b6001600160a01b0383161580159061122457506001600160a01b03821615155b15611234576112348383836113f9565b505050565b8415610ba457866001600160a01b031663edd9444b60405180606001604052808989808060200260200160405190810160405280939291908181526020016000905b828210156112a757611298604083028601368190038101906124ee565b8152602001906001019061127b565b50505050508152602001878152602001868152506112c5898961141d565b3386866040518663ffffffff1660e01b8152600401610b7195949392919061259d565b60006001600160a01b0382161561137f576040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa158015611356573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061137a9190612654565b6102df565b4792915050565b8115611234576001600160a01b03811661139d5750335b6001600160a01b0383166113be576112346001600160a01b038216836114ea565b6112346001600160a01b03841682846115b3565b61107182827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b6112346001600160a01b0384168383611627565b60606111308484846116eb61171d565b60608167ffffffffffffffff811115611438576114386119d4565b60405190808252806020026020018201604052801561147d57816020015b60408051808201909152600080825260208201528152602001906001900390816114565790505b50905060005b81518110156104ef576040518060400160405280306001600160a01b031681526020018585848181106114b8576114b8612096565b905060400201602001358152508282815181106114d7576114d7612096565b6020908102919091010152600101611483565b80471015611526576040517fcd78605900000000000000000000000000000000000000000000000000000000815230600482015260240161038a565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114611573576040519150601f19603f3d011682016040523d82523d6000602084013e611578565b606091505b5050905080611234576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b0383811660248301526044820183905261123491859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506117d5565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b3000000000000000000000000000000000000000000000000000000001790526116a68482611851565b6116e5576040516001600160a01b038481166024830152600060448301526116db91869182169063095ea7b3906064016115e0565b6116e584826117d5565b50505050565b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608247101561175b576040517fcd78605900000000000000000000000000000000000000000000000000000000815230600482015260240161038a565b600080866001600160a01b0316858760405161177791906123b5565b60006040518083038185875af1925050503d80600081146117b4576040519150601f19603f3d011682016040523d82523d6000602084013e6117b9565b606091505b50915091506117ca878383876118f4565b979650505050505050565b60006117ea6001600160a01b03841683611965565b9050805160001415801561180f57508080602001905181019061180d919061266d565b155b15611234576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b038416600482015260240161038a565b6000806000846001600160a01b03168460405161186e91906123b5565b6000604051808303816000865af19150503d80600081146118ab576040519150601f19603f3d011682016040523d82523d6000602084013e6118b0565b606091505b50915091508180156118da5750805115806118da5750808060200190518101906118da919061266d565b801561103d5750505050506001600160a01b03163b151590565b6060831561195b57825160000361195457846001600160a01b03163b600003611954576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b038616600482015260240161038a565b5081611130565b6111308383611976565b6060610340838360006116eb61171d565b8151156119865781518083602001fd5b6116eb8163ffffffff16565b6000602082840312156119a457600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461034057600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516060810167ffffffffffffffff81118282101715611a2657611a266119d4565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611a7357611a736119d4565b604052919050565b600067ffffffffffffffff821115611a9557611a956119d4565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60008060408385031215611ad457600080fd5b82359150602083013567ffffffffffffffff811115611af257600080fd5b8301601f81018513611b0357600080fd5b8035611b16611b1182611a7b565b611a2c565b818152866020838501011115611b2b57600080fd5b816020840160208301376000602083830101528093505050509250929050565b60008083601f840112611b5d57600080fd5b50813567ffffffffffffffff811115611b7557600080fd5b6020830191508360208260061b8501011115611b9057600080fd5b9250929050565b60008083601f840112611ba957600080fd5b50813567ffffffffffffffff811115611bc157600080fd5b6020830191508360208260051b8501011115611b9057600080fd5b60008060008060008060008060a0898b031215611bf857600080fd5b883567ffffffffffffffff80821115611c1057600080fd5b908a01906080828d031215611c2457600080fd5b90985060208a01359080821115611c3a57600080fd5b611c468c838d01611b4b565b909950975060408b0135915080821115611c5f57600080fd5b611c6b8c838d01611b97565b909750955060608b0135915080821115611c8457600080fd5b50611c918b828c01611b97565b999c989b50969995989497949560800135949350505050565b60005b83811015611cc5578181015183820152602001611cad565b50506000910152565b60008151808452611ce6816020860160208601611caa565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000604082016040835280855180835260608501915060608160051b8601019250602080880160005b83811015611d8d577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0888703018552611d7b868351611cce565b95509382019390820190600101611d41565b50508584038187015286518085528782019482019350915060005b82811015611dc457845184529381019392810192600101611da8565b5091979650505050505050565b60008060208385031215611de457600080fd5b823567ffffffffffffffff811115611dfb57600080fd5b611e0785828601611b97565b90969095509350505050565b8051151582526000602082015160606020850152611e346060850182611cce565b604093840151949093019390935250919050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015611ebb577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452611ea9858351611e13565b94509285019290850190600101611e6f565b5092979650505050505050565b600060208284031215611eda57600080fd5b813567ffffffffffffffff811115611ef157600080fd5b8201610180818503121561034057600080fd5b60008060208385031215611f1757600080fd5b823567ffffffffffffffff80821115611f2f57600080fd5b818501915085601f830112611f4357600080fd5b813581811115611f5257600080fd5b866020828501011115611f6457600080fd5b60209290920196919550909350505050565b60008060008060008060008060a0898b031215611f9257600080fd5b883567ffffffffffffffff80821115611faa57600080fd5b908a01906060828d031215611c2457600080fd5b600060208284031215611fd057600080fd5b813567ffffffffffffffff811115611fe757600080fd5b82016101a0818503121561034057600080fd5b80356001600160a01b038116811461201157600080fd5b919050565b60006020828403121561202857600080fd5b61034082611ffa565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261206657600080fd5b83018035915067ffffffffffffffff82111561208157600080fd5b602001915036819003821315611b9057600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612125576121256120c5565b5060010190565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261216157600080fd5b83018035915067ffffffffffffffff82111561217c57600080fd5b6020019150600681901b3603821315611b9057600080fd5b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b60006101006001600160a01b03808d16845260028c10612226577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8b6020850152808b166040850152808a1660608501528860808501528760a085015280871660c0850152508060e08401526122648184018587612194565b9c9b505050505050505050505050565b8183823760009101908152919050565b818103818111156102df576102df6120c5565b6020815260006103406020830184611e13565b60006101006122cd83895180516001600160a01b03168252602090810151910152565b6020880151604084015260408801516060840152612301608084018880516001600160a01b03168252602090810151910152565b6001600160a01b03861660c08401528060e08401526123238184018587612194565b98975050505050505050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa183360301811261236357600080fd5b9190910192915050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc183360301811261236357600080fd5b602081526000611130602083018486612194565b60008251612363818460208701611caa565b8051801515811461201157600080fd5b600060208083850312156123ea57600080fd5b825167ffffffffffffffff8082111561240257600080fd5b908401906060828703121561241657600080fd5b61241e611a03565b612427836123c7565b8152838301518281111561243a57600080fd5b83019150601f8201871361244d57600080fd5b815161245b611b1182611a7b565b818152888683860101111561246f57600080fd5b61247e82878301888701611caa565b80868401525050604083015160408201528094505050505092915050565b80820281158282048414176102df576102df6120c5565b6000826124e9577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60006040828403121561250057600080fd5b6040516040810181811067ffffffffffffffff82111715612523576125236119d4565b60405261252f83611ffa565b8152602083013560208201528091505092915050565b600081518084526020808501945080840160005b838110156125925761257f87835180516001600160a01b03168252602090810151910152565b6040969096019590820190600101612559565b509495945050505050565b60808152600060e082018751606060808501528181518084526101008601915060209350838301925060005b81811015612602576125ef83855180516001600160a01b03168252602090810151910152565b92840192604092909201916001016125c9565b5050828a015160a086015260408a015160c086015284810383860152612628818a612545565b9250505061264160408401876001600160a01b03169052565b8281036060840152612323818587612194565b60006020828403121561266657600080fd5b5051919050565b60006020828403121561267f57600080fd5b610340826123c756

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

000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3

-----Decoded View---------------
Arg [0] : _permit2 (address): 0x000000000022D473030F116dDEE9F6B43aC78BA3

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3


Block Transaction Gas Used Reward
view all blocks produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ Download: CSV Export  ]
[ 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.