ETH Price: $2,348.42 (-0.05%)
 

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To
Sell Order Swap1085539192023-08-22 12:16:55895 days ago1692706615IN
0x227F070E...e8edC6C0f
0 ETH0.0002265609920.0000009
Sell Order Swap1085363922023-08-22 2:32:41895 days ago1692671561IN
0x227F070E...e8edC6C0f
0 ETH0.0002727228970.01
Sell Order Swap1085363582023-08-22 2:31:33895 days ago1692671493IN
0x227F070E...e8edC6C0f
0 ETH0.0001979013390.01
Sell Order Swap1085362442023-08-22 2:27:45895 days ago1692671265IN
0x227F070E...e8edC6C0f
0 ETH0.0002137335880.000001
Sell Order Swap1085362062023-08-22 2:26:29895 days ago1692671189IN
0x227F070E...e8edC6C0f
0 ETH0.0002645236610.0000002
Sell Order Swap1085351562023-08-22 1:51:29895 days ago1692669089IN
0x227F070E...e8edC6C0f
0 ETH0.0002919414730.0077601
Sell Order Swap1085094762023-08-21 11:35:29896 days ago1692617729IN
0x227F070E...e8edC6C0f
0 ETH0.0003079910640.0120001
Sell Order Swap1084788732023-08-20 18:35:23897 days ago1692556523IN
0x227F070E...e8edC6C0f
0.0085 ETH0.0006407056370.0716955
Sell Order Swap1084788352023-08-20 18:34:07897 days ago1692556447IN
0x227F070E...e8edC6C0f
0 ETH0.0001719520680.0716955
Sell Order Swap1084788112023-08-20 18:33:19897 days ago1692556399IN
0x227F070E...e8edC6C0f
0 ETH0.0003526207930.0250014
Sell Order Swap1084787792023-08-20 18:32:15897 days ago1692556335IN
0x227F070E...e8edC6C0f
0 ETH0.0002888303360.0250014
Sell Order Swap1084787252023-08-20 18:30:27897 days ago1692556227IN
0x227F070E...e8edC6C0f
0 ETH0.0003981317470.0000004
Sell Order Swap1084774072023-08-20 17:46:31897 days ago1692553591IN
0x227F070E...e8edC6C0f
0 ETH0.000382804720.00000785
Sell Order Swap1084773132023-08-20 17:43:23897 days ago1692553403IN
0x227F070E...e8edC6C0f
0.02 ETH0.0001422881860.00000941
Sell Order Swap1084765622023-08-20 17:18:21897 days ago1692551901IN
0x227F070E...e8edC6C0f
0 ETH0.0002661225850.0000097
Sell Order Swap1084765052023-08-20 17:16:27897 days ago1692551787IN
0x227F070E...e8edC6C0f
0 ETH0.000130018280.0007228
Buy Order Swap1084745712023-08-20 16:11:59897 days ago1692547919IN
0x227F070E...e8edC6C0f
0.000371104146956 ETH0.0002715099090.10000006
Sell Order Swap1084682622023-08-20 12:41:41897 days ago1692535301IN
0x227F070E...e8edC6C0f
0 ETH0.0000891391350.0002001
Sell Order Swap1084677092023-08-20 12:23:15897 days ago1692534195IN
0x227F070E...e8edC6C0f
0 ETH0.0002228456460.0000054
Sell Order Swap1084647722023-08-20 10:45:21897 days ago1692528321IN
0x227F070E...e8edC6C0f
0.183 ETH0.0000667880630.0000002
Sell Order Swap1084617102023-08-20 9:03:17897 days ago1692522197IN
0x227F070E...e8edC6C0f
0.43 ETH0.0001969729640.01
Sell Order Swap1084616472023-08-20 9:01:11897 days ago1692522071IN
0x227F070E...e8edC6C0f
0.65 ETH0.0000593358020.0000003
Sell Order Swap1084613392023-08-20 8:50:55897 days ago1692521455IN
0x227F070E...e8edC6C0f
0.975 ETH0.0001844317920.0000002
Sell Order Swap1084570172023-08-20 6:26:51897 days ago1692512811IN
0x227F070E...e8edC6C0f
0 ETH0.0001893400550.0000011
Sell Order Swap1084546662023-08-20 5:08:29897 days ago1692508109IN
0x227F070E...e8edC6C0f
0 ETH0.0006169524990.10000005
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To
1085539192023-08-22 12:16:55895 days ago1692706615
0x227F070E...e8edC6C0f
0.011301505882328 ETH
1085539192023-08-22 12:16:55895 days ago1692706615
0x227F070E...e8edC6C0f
0.011301505882328 ETH
1085104272023-08-21 12:07:11896 days ago1692619631
0x227F070E...e8edC6C0f
0.000122824263081 ETH
1085104272023-08-21 12:07:11896 days ago1692619631
0x227F070E...e8edC6C0f
0.000122824263081 ETH
1085094762023-08-21 11:35:29896 days ago1692617729
0x227F070E...e8edC6C0f
0.000598793608014 ETH
1085094762023-08-21 11:35:29896 days ago1692617729
0x227F070E...e8edC6C0f
0.000598793608014 ETH
1085071582023-08-21 10:18:13896 days ago1692613093
0x227F070E...e8edC6C0f
0.001 ETH
1085071582023-08-21 10:18:13896 days ago1692613093
0x227F070E...e8edC6C0f
0.001 ETH
1085046132023-08-21 8:53:23896 days ago1692608003
0x227F070E...e8edC6C0f
0.011358955636552 ETH
1085046132023-08-21 8:53:23896 days ago1692608003
0x227F070E...e8edC6C0f
0.011358955636552 ETH
1084985742023-08-21 5:32:05896 days ago1692595925
0x227F070E...e8edC6C0f
0.159342072665246 ETH
1084985742023-08-21 5:32:05896 days ago1692595925
0x227F070E...e8edC6C0f
0.159342072665246 ETH
1084966182023-08-21 4:26:53896 days ago1692592013
0x227F070E...e8edC6C0f
0.003000000532636 ETH
1084966182023-08-21 4:26:53896 days ago1692592013
0x227F070E...e8edC6C0f
0.003000000532636 ETH
1084964962023-08-21 4:22:49896 days ago1692591769
0x227F070E...e8edC6C0f
0.003 ETH
1084964962023-08-21 4:22:49896 days ago1692591769
0x227F070E...e8edC6C0f
0.003 ETH
1084940982023-08-21 3:02:53896 days ago1692586973
0x227F070E...e8edC6C0f
0.005816972908189 ETH
1084940982023-08-21 3:02:53896 days ago1692586973
0x227F070E...e8edC6C0f
0.005816972908189 ETH
1084909582023-08-21 1:18:13896 days ago1692580693
0x227F070E...e8edC6C0f
0.004255275969534 ETH
1084909582023-08-21 1:18:13896 days ago1692580693
0x227F070E...e8edC6C0f
0.004255275969534 ETH
1084840232023-08-20 21:27:03896 days ago1692566823
0x227F070E...e8edC6C0f
0.0006 ETH
1084840232023-08-20 21:27:03896 days ago1692566823
0x227F070E...e8edC6C0f
0.0006 ETH
1084788732023-08-20 18:35:23897 days ago1692556523
0x227F070E...e8edC6C0f
0.0085 ETH
1084773132023-08-20 17:43:23897 days ago1692553403
0x227F070E...e8edC6C0f
0.02 ETH
1084750842023-08-20 16:29:05897 days ago1692548945
0x227F070E...e8edC6C0f
0.026182172520169 ETH
View All Internal Transactions

Cross-Chain Transactions
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 17 : 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) { }
}

// 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 17 : BasePermit2Adapter.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;

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 {
  /// @inheritdoc IBasePermit2Adapter
  address public constant NATIVE_TOKEN = Token.NATIVE_TOKEN;
  /// @inheritdoc IBasePermit2Adapter
  // solhint-disable-next-line var-name-mixedcase
  IPermit2 public immutable PERMIT2;

  constructor(IPermit2 _permit2) {
    PERMIT2 = _permit2;
  }

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

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

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;

import { Address } from "@openzeppelin/contracts/utils/Address.sol";
// 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;
  using Address for address;

  /// @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] =
        _contractCalls[i].target.functionCallWithValue(_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;
      }
    }
  }
}

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;

import { Address } from "@openzeppelin/contracts/utils/Address.sol";
// 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;
  using Address 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;
    _params.swapper.functionCallWithValue(_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;
  }

  /// @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;
    _params.swapper.functionCallWithValue(_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;
  }
}

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

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

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

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

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

// 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 (address(_token) != Token.NATIVE_TOKEN) {
      _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;
      }
    }
  }
}

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

// 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 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;
  }

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

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

// 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;
}

// 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;
    }
}

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

// 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": [
    "@call-simulation/=lib/call-simulation/src/",
    "@openzeppelin/=lib/openzeppelin-contracts/",
    "@prb/test/=lib/prb-test/src/",
    "call-simulation/=lib/call-simulation/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "openzeppelin/=lib/openzeppelin-contracts/contracts/",
    "prb-test/=lib/prb-test/src/",
    "src/=src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 10000
  },
  "metadata": {
    "bytecodeHash": "none",
    "appendCBOR": false
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "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":[{"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"},{"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":"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":[{"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":"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"}]

60a06040523480156200001157600080fd5b506040516200263138038062002631833981016040819052620000349162000046565b6001600160a01b031660805262000078565b6000602082840312156200005957600080fd5b81516001600160a01b03811681146200007157600080fd5b9392505050565b60805161258f620000a2600039600081816101900152818161031401526109b9015261258f6000f3fe60806040526004361061009a5760003560e01c80635e547fc011610069578063ad271b311161004e578063ad271b31146101b2578063bcbef206146101c5578063ee4cfaf7146101da57600080fd5b80635e547fc0146101565780636afdd8501461017e57600080fd5b806301ffc9a7146100a65780632c8aaabe146100db57806331f7d964146100fc5780633ed242b41461013657600080fd5b366100a157005b600080fd5b3480156100b257600080fd5b506100c66100c1366004611978565b6101ed565b60405190151581526020015b60405180910390f35b6100ee6100e9366004611a4b565b610286565b6040516100d2929190611b87565b34801561010857600080fd5b50610111600081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100d2565b610149610144366004611c40565b61035f565b6040516100d29190611cb7565b610169610164366004611d37565b610442565b604080519283526020830191909152016100d2565b34801561018a57600080fd5b506101117f000000000000000000000000000000000000000000000000000000000000000081565b6101696101c0366004611d73565b610685565b6101d86101d3366004611daf565b610865565b005b6100ee6101e8366004611e21565b610938565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f3ed242b400000000000000000000000000000000000000000000000000000000148061028057507fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000145b92915050565b60608082804211156102d2576040517f25f14a28000000000000000000000000000000000000000000000000000000008152426004820152602481018290526044015b60405180910390fd5b61033f6102e260208d018d611e92565b8c602001358d60400135878f80606001906102fd9190611ead565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169594939291906109e4565b61034d8a8a8a8a8a8a610ad0565b92509250509850989650505050505050565b60608167ffffffffffffffff81111561037a5761037a611f12565b6040519080825280602002602001820160405280156103d157816020015b6103be604051806060016040528060001515815260200160608152602001600081525090565b8152602001906001900390816103985790505b50905060005b8281101561043b5761040b8484838181106103f4576103f4611f41565b90506020028101906104069190611ead565b610e0e565b82828151811061041d5761041d611f41565b6020026020010181905250808061043390611f9f565b9150506103d7565b5092915050565b60008082354281101561048a576040517f25f14a28000000000000000000000000000000000000000000000000000000008152426004820152602481018290526044016102c9565b6104b661049d6040860160208701611e92565b6040860135606087013587356102fd60808a018a611ead565b6104f56104c960c0860160a08701611e92565b6104d96040870160208801611e92565b73ffffffffffffffffffffffffffffffffffffffff1690610fc2565b6000806105086040870160208801611e92565b73ffffffffffffffffffffffffffffffffffffffff161461052a576000610530565b84604001355b90506105a661054260e0870187611ead565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525085925061058991505060e0890160c08a01611e92565b73ffffffffffffffffffffffffffffffffffffffff169190610ff1565b506105e76105b8610140870187611fd7565b6105ca61012089016101008a01611e92565b73ffffffffffffffffffffffffffffffffffffffff169190611009565b9250846101200135831015610636576040517f763dfca00000000000000000000000000000000000000000000000000000000081526004810184905261012086013560248201526044016102c9565b61067861064960c0870160a08801611e92565b600161065b6040890160208a01611e92565b73ffffffffffffffffffffffffffffffffffffffff1691906110d5565b5050604090920135929050565b6000808235428110156106cd576040517f25f14a28000000000000000000000000000000000000000000000000000000008152426004820152602481018290526044016102c9565b6106e061049d6040860160208701611e92565b6106f36104c960c0860160a08701611e92565b6000806107066040870160208801611e92565b73ffffffffffffffffffffffffffffffffffffffff161461072857600061072e565b84604001355b905061074061054260e0870187611ead565b5060006107716107566040880160208901611e92565b73ffffffffffffffffffffffffffffffffffffffff16611124565b9050610796610784610140880188611fd7565b6105ca6101208a016101008b01611e92565b93508561012001358410156107e5576040517f763dfca00000000000000000000000000000000000000000000000000000000081526004810185905261012087013560248201526044016102c9565b610828816107fb61018089016101608a01611e92565b61080b60408a0160208b01611e92565b73ffffffffffffffffffffffffffffffffffffffff1691906111dc565b61084d61083b60c0880160a08901611e92565b600161065b60408a0160208b01611e92565b61085b81604088013561203f565b9450505050915091565b60005a90506000803073ffffffffffffffffffffffffffffffffffffffff168585604051610894929190612052565b600060405180830381855af49150503d80600081146108cf576040519150601f19603f3d011682016040523d82523d6000602084013e6108d4565b606091505b509150915060005a6108e6908561203f565b905060405180606001604052808415158152602001838152602001828152506040517f493703af0000000000000000000000000000000000000000000000000000000081526004016102c99190612062565b606080828042111561097f576040517f25f14a28000000000000000000000000000000000000000000000000000000008152426004820152602481018290526044016102c9565b61033f61098c8c80611fd7565b8d60200135878f80604001906109a29190611ead565b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001695949392919061125c565b73ffffffffffffffffffffffffffffffffffffffff861615610ac7576040805160a08101825273ffffffffffffffffffffffffffffffffffffffff8881166060830190815260808301899052825260208083018890528284018790528351808501855230815290810189905292517f30f28b7a000000000000000000000000000000000000000000000000000000008152908a16926330f28b7a92610a94929091903390889088906004016120be565b600060405180830381600087803b158015610aae57600080fd5b505af1158015610ac2573d6000803e3d6000fd5b505050505b50505050505050565b60608060005b87811015610b5757610b4f898983818110610af357610af3611f41565b9050604002016020016020810190610b0b9190611e92565b8a8a84818110610b1d57610b1d611f41565b610b339260206040909202019081019150611e92565b73ffffffffffffffffffffffffffffffffffffffff1690611318565b600101610ad6565b508467ffffffffffffffff811115610b7157610b71611f12565b604051908082528060200260200182016040528015610ba457816020015b6060815260200190600190039081610b8f5790505b50915060005b85811015610c9d57610c78878783818110610bc757610bc7611f41565b9050602002810190610bd9919061216a565b610be7906020810190611ead565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508b92508a9150859050818110610c3057610c30611f41565b9050602002810190610c42919061216a565b60400135898985818110610c5857610c58611f41565b9050602002810190610c6a919061216a565b610589906020810190611e92565b838281518110610c8a57610c8a611f41565b6020908102919091010152600101610baa565b5060005b87811015610d2557610d1d898983818110610cbe57610cbe611f41565b9050604002016020016020810190610cd69190611e92565b60018b8b85818110610cea57610cea611f41565b610d009260206040909202019081019150611e92565b73ffffffffffffffffffffffffffffffffffffffff16919061133f565b600101610ca1565b508267ffffffffffffffff811115610d3f57610d3f611f12565b604051908082528060200260200182016040528015610d68578160200160208202803683370190505b50905060005b83811015610e0257610ddd858583818110610d8b57610d8b611f41565b9050602002810190610d9d91906121a8565b610dab906020810190611fd7565b878785818110610dbd57610dbd611f41565b9050602002810190610dcf91906121a8565b6105ca906020810190611e92565b828281518110610def57610def611f41565b6020908102919091010152600101610d6e565b50965096945050505050565b610e34604051806060016040528060001515815260200160608152602001600081525090565b6000803073ffffffffffffffffffffffffffffffffffffffff1663bcbef20660e01b8686604051602401610e699291906121dc565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529051610ef291906121f0565b600060405180830381855af49150503d8060008114610f2d576040519150601f19603f3d011682016040523d82523d6000602084013e610f32565b606091505b50915091508115610f9f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f5754463f2053686f756c642068617665206661696c656421000000000000000060448201526064016102c9565b60048101905080806020019051810190610fb9919061228a565b95945050505050565b610fed82827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6110d5565b5050565b6060611001848484611360611392565b949350505050565b600061101484611124565b90508060005b61102560018561203f565b8110156110ab57600061271086868481811061104357611043611f41565b9050604002016020013585611058919061237c565b6110629190612393565b9050611096878288888681811061107b5761107b611f41565b6110919260206040909202019081019150611e92565b6111dc565b6110a0818461203f565b92505060010161101a565b506110cd858286866110be60018261203f565b81811061107b5761107b611f41565b509392505050565b73ffffffffffffffffffffffffffffffffffffffff83161580159061110f575073ffffffffffffffffffffffffffffffffffffffff821615155b1561111f5761111f83838361133f565b505050565b600073ffffffffffffffffffffffffffffffffffffffff8216156111d5576040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8316906370a0823190602401602060405180830381865afa1580156111ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111d091906123ce565b610280565b4792915050565b811561111f5773ffffffffffffffffffffffffffffffffffffffff81166112005750335b73ffffffffffffffffffffffffffffffffffffffff831661123b5761111f73ffffffffffffffffffffffffffffffffffffffff821683611457565b61111f73ffffffffffffffffffffffffffffffffffffffff8416828461152d565b8415610ac7578673ffffffffffffffffffffffffffffffffffffffff1663edd9444b60405180606001604052808989808060200260200160405190810160405280939291908181526020016000905b828210156112d7576112c8604083028601368190038101906123e7565b815260200190600101906112ab565b50505050508152602001878152602001868152506112f589896115ae565b3386866040518663ffffffff1660e01b8152600401610a949594939291906124a3565b610fed82827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b61111f73ffffffffffffffffffffffffffffffffffffffff84168383611688565b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6060824710156113d0576040517fcd7860590000000000000000000000000000000000000000000000000000000081523060048201526024016102c9565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516113f991906121f0565b60006040518083038185875af1925050503d8060008114611436576040519150601f19603f3d011682016040523d82523d6000602084013e61143b565b606091505b509150915061144c87838387611766565b979650505050505050565b80471015611493576040517fcd7860590000000000000000000000000000000000000000000000000000000081523060048201526024016102c9565b60008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d80600081146114ed576040519150601f19603f3d011682016040523d82523d6000602084013e6114f2565b606091505b505090508061111f576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405173ffffffffffffffffffffffffffffffffffffffff83811660248301526044820183905261111f91859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506117f1565b60608167ffffffffffffffff8111156115c9576115c9611f12565b60405190808252806020026020018201604052801561160e57816020015b60408051808201909152600080825260208201528152602001906001900390816115e75790505b50905060005b815181101561043b5760405180604001604052803073ffffffffffffffffffffffffffffffffffffffff16815260200185858481811061165657611656611f41565b9050604002016020013581525082828151811061167557611675611f41565b6020908102919091010152600101611614565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b3000000000000000000000000000000000000000000000000000000001790526117148482611887565b6117605760405173ffffffffffffffffffffffffffffffffffffffff84811660248301526000604483015261175691869182169063095ea7b390606401611567565b61176084826117f1565b50505050565b606083156117e75782516000036117e0578473ffffffffffffffffffffffffffffffffffffffff163b6000036117e0576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff861660048201526024016102c9565b5081611001565b6110018383611944565b600061181373ffffffffffffffffffffffffffffffffffffffff841683611960565b905080516000141580156118385750808060200190518101906118369190612574565b155b1561111f576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841660048201526024016102c9565b60008060008473ffffffffffffffffffffffffffffffffffffffff16846040516118b191906121f0565b6000604051808303816000865af19150503d80600081146118ee576040519150601f19603f3d011682016040523d82523d6000602084013e6118f3565b606091505b509150915081801561191d57508051158061191d57508080602001905181019061191d9190612574565b8015610fb957505050505073ffffffffffffffffffffffffffffffffffffffff163b151590565b8151156119545781518083602001fd5b6113608163ffffffff16565b606061197183836000611360611392565b9392505050565b60006020828403121561198a57600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461197157600080fd5b60008083601f8401126119cc57600080fd5b50813567ffffffffffffffff8111156119e457600080fd5b6020830191508360208260061b85010111156119ff57600080fd5b9250929050565b60008083601f840112611a1857600080fd5b50813567ffffffffffffffff811115611a3057600080fd5b6020830191508360208260051b85010111156119ff57600080fd5b60008060008060008060008060a0898b031215611a6757600080fd5b883567ffffffffffffffff80821115611a7f57600080fd5b908a01906080828d031215611a9357600080fd5b90985060208a01359080821115611aa957600080fd5b611ab58c838d016119ba565b909950975060408b0135915080821115611ace57600080fd5b611ada8c838d01611a06565b909750955060608b0135915080821115611af357600080fd5b50611b008b828c01611a06565b999c989b50969995989497949560800135949350505050565b60005b83811015611b34578181015183820152602001611b1c565b50506000910152565b60008151808452611b55816020860160208601611b19565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000604082016040835280855180835260608501915060608160051b8601019250602080880160005b83811015611bfc577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0888703018552611bea868351611b3d565b95509382019390820190600101611bb0565b50508584038187015286518085528782019482019350915060005b82811015611c3357845184529381019392810192600101611c17565b5091979650505050505050565b60008060208385031215611c5357600080fd5b823567ffffffffffffffff811115611c6a57600080fd5b611c7685828601611a06565b90969095509350505050565b8051151582526000602082015160606020850152611ca36060850182611b3d565b604093840151949093019390935250919050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015611d2a577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452611d18858351611c82565b94509285019290850190600101611cde565b5092979650505050505050565b600060208284031215611d4957600080fd5b813567ffffffffffffffff811115611d6057600080fd5b8201610160818503121561197157600080fd5b600060208284031215611d8557600080fd5b813567ffffffffffffffff811115611d9c57600080fd5b8201610180818503121561197157600080fd5b60008060208385031215611dc257600080fd5b823567ffffffffffffffff80821115611dda57600080fd5b818501915085601f830112611dee57600080fd5b813581811115611dfd57600080fd5b866020828501011115611e0f57600080fd5b60209290920196919550909350505050565b60008060008060008060008060a0898b031215611e3d57600080fd5b883567ffffffffffffffff80821115611e5557600080fd5b908a01906060828d031215611a9357600080fd5b803573ffffffffffffffffffffffffffffffffffffffff81168114611e8d57600080fd5b919050565b600060208284031215611ea457600080fd5b61197182611e69565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112611ee257600080fd5b83018035915067ffffffffffffffff821115611efd57600080fd5b6020019150368190038213156119ff57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611fd057611fd0611f70565b5060010190565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261200c57600080fd5b83018035915067ffffffffffffffff82111561202757600080fd5b6020019150600681901b36038213156119ff57600080fd5b8181038181111561028057610280611f70565b8183823760009101908152919050565b6020815260006119716020830184611c82565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b60006101006120ee838951805173ffffffffffffffffffffffffffffffffffffffff168252602090810151910152565b602088015160408401526040880151606084015261212f6080840188805173ffffffffffffffffffffffffffffffffffffffff168252602090810151910152565b73ffffffffffffffffffffffffffffffffffffffff861660c08401528060e084015261215e8184018587612075565b98975050505050505050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa183360301811261219e57600080fd5b9190910192915050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc183360301811261219e57600080fd5b602081526000611001602083018486612075565b6000825161219e818460208701611b19565b6040516060810167ffffffffffffffff8111828210171561222557612225611f12565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561227257612272611f12565b604052919050565b80518015158114611e8d57600080fd5b6000602080838503121561229d57600080fd5b825167ffffffffffffffff808211156122b557600080fd5b90840190606082870312156122c957600080fd5b6122d1612202565b6122da8361227a565b815283830151828111156122ed57600080fd5b8301601f810188136122fe57600080fd5b80518381111561231057612310611f12565b612340867fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160161222b565b9350808452888682840101111561235657600080fd5b61236581878601888501611b19565b505092830152604090810151908201529392505050565b808202811582820484141761028057610280611f70565b6000826123c9577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000602082840312156123e057600080fd5b5051919050565b6000604082840312156123f957600080fd5b6040516040810181811067ffffffffffffffff8211171561241c5761241c611f12565b60405261242883611e69565b8152602083013560208201528091505092915050565b600081518084526020808501945080840160005b8381101561249857612485878351805173ffffffffffffffffffffffffffffffffffffffff168252602090810151910152565b6040969096019590820190600101612452565b509495945050505050565b60808152600060e082018751606060808501528181518084526101008601915060209350838301925060005b8181101561251557612502838551805173ffffffffffffffffffffffffffffffffffffffff168252602090810151910152565b92840192604092909201916001016124cf565b5050828a015160a086015260408a015160c08601528481038386015261253b818a61243e565b92505050612561604084018773ffffffffffffffffffffffffffffffffffffffff169052565b828103606084015261215e818587612075565b60006020828403121561258657600080fd5b6119718261227a56000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3

Deployed Bytecode

0x60806040526004361061009a5760003560e01c80635e547fc011610069578063ad271b311161004e578063ad271b31146101b2578063bcbef206146101c5578063ee4cfaf7146101da57600080fd5b80635e547fc0146101565780636afdd8501461017e57600080fd5b806301ffc9a7146100a65780632c8aaabe146100db57806331f7d964146100fc5780633ed242b41461013657600080fd5b366100a157005b600080fd5b3480156100b257600080fd5b506100c66100c1366004611978565b6101ed565b60405190151581526020015b60405180910390f35b6100ee6100e9366004611a4b565b610286565b6040516100d2929190611b87565b34801561010857600080fd5b50610111600081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100d2565b610149610144366004611c40565b61035f565b6040516100d29190611cb7565b610169610164366004611d37565b610442565b604080519283526020830191909152016100d2565b34801561018a57600080fd5b506101117f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba381565b6101696101c0366004611d73565b610685565b6101d86101d3366004611daf565b610865565b005b6100ee6101e8366004611e21565b610938565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f3ed242b400000000000000000000000000000000000000000000000000000000148061028057507fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000145b92915050565b60608082804211156102d2576040517f25f14a28000000000000000000000000000000000000000000000000000000008152426004820152602481018290526044015b60405180910390fd5b61033f6102e260208d018d611e92565b8c602001358d60400135878f80606001906102fd9190611ead565b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3169594939291906109e4565b61034d8a8a8a8a8a8a610ad0565b92509250509850989650505050505050565b60608167ffffffffffffffff81111561037a5761037a611f12565b6040519080825280602002602001820160405280156103d157816020015b6103be604051806060016040528060001515815260200160608152602001600081525090565b8152602001906001900390816103985790505b50905060005b8281101561043b5761040b8484838181106103f4576103f4611f41565b90506020028101906104069190611ead565b610e0e565b82828151811061041d5761041d611f41565b6020026020010181905250808061043390611f9f565b9150506103d7565b5092915050565b60008082354281101561048a576040517f25f14a28000000000000000000000000000000000000000000000000000000008152426004820152602481018290526044016102c9565b6104b661049d6040860160208701611e92565b6040860135606087013587356102fd60808a018a611ead565b6104f56104c960c0860160a08701611e92565b6104d96040870160208801611e92565b73ffffffffffffffffffffffffffffffffffffffff1690610fc2565b6000806105086040870160208801611e92565b73ffffffffffffffffffffffffffffffffffffffff161461052a576000610530565b84604001355b90506105a661054260e0870187611ead565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525085925061058991505060e0890160c08a01611e92565b73ffffffffffffffffffffffffffffffffffffffff169190610ff1565b506105e76105b8610140870187611fd7565b6105ca61012089016101008a01611e92565b73ffffffffffffffffffffffffffffffffffffffff169190611009565b9250846101200135831015610636576040517f763dfca00000000000000000000000000000000000000000000000000000000081526004810184905261012086013560248201526044016102c9565b61067861064960c0870160a08801611e92565b600161065b6040890160208a01611e92565b73ffffffffffffffffffffffffffffffffffffffff1691906110d5565b5050604090920135929050565b6000808235428110156106cd576040517f25f14a28000000000000000000000000000000000000000000000000000000008152426004820152602481018290526044016102c9565b6106e061049d6040860160208701611e92565b6106f36104c960c0860160a08701611e92565b6000806107066040870160208801611e92565b73ffffffffffffffffffffffffffffffffffffffff161461072857600061072e565b84604001355b905061074061054260e0870187611ead565b5060006107716107566040880160208901611e92565b73ffffffffffffffffffffffffffffffffffffffff16611124565b9050610796610784610140880188611fd7565b6105ca6101208a016101008b01611e92565b93508561012001358410156107e5576040517f763dfca00000000000000000000000000000000000000000000000000000000081526004810185905261012087013560248201526044016102c9565b610828816107fb61018089016101608a01611e92565b61080b60408a0160208b01611e92565b73ffffffffffffffffffffffffffffffffffffffff1691906111dc565b61084d61083b60c0880160a08901611e92565b600161065b60408a0160208b01611e92565b61085b81604088013561203f565b9450505050915091565b60005a90506000803073ffffffffffffffffffffffffffffffffffffffff168585604051610894929190612052565b600060405180830381855af49150503d80600081146108cf576040519150601f19603f3d011682016040523d82523d6000602084013e6108d4565b606091505b509150915060005a6108e6908561203f565b905060405180606001604052808415158152602001838152602001828152506040517f493703af0000000000000000000000000000000000000000000000000000000081526004016102c99190612062565b606080828042111561097f576040517f25f14a28000000000000000000000000000000000000000000000000000000008152426004820152602481018290526044016102c9565b61033f61098c8c80611fd7565b8d60200135878f80604001906109a29190611ead565b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba31695949392919061125c565b73ffffffffffffffffffffffffffffffffffffffff861615610ac7576040805160a08101825273ffffffffffffffffffffffffffffffffffffffff8881166060830190815260808301899052825260208083018890528284018790528351808501855230815290810189905292517f30f28b7a000000000000000000000000000000000000000000000000000000008152908a16926330f28b7a92610a94929091903390889088906004016120be565b600060405180830381600087803b158015610aae57600080fd5b505af1158015610ac2573d6000803e3d6000fd5b505050505b50505050505050565b60608060005b87811015610b5757610b4f898983818110610af357610af3611f41565b9050604002016020016020810190610b0b9190611e92565b8a8a84818110610b1d57610b1d611f41565b610b339260206040909202019081019150611e92565b73ffffffffffffffffffffffffffffffffffffffff1690611318565b600101610ad6565b508467ffffffffffffffff811115610b7157610b71611f12565b604051908082528060200260200182016040528015610ba457816020015b6060815260200190600190039081610b8f5790505b50915060005b85811015610c9d57610c78878783818110610bc757610bc7611f41565b9050602002810190610bd9919061216a565b610be7906020810190611ead565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508b92508a9150859050818110610c3057610c30611f41565b9050602002810190610c42919061216a565b60400135898985818110610c5857610c58611f41565b9050602002810190610c6a919061216a565b610589906020810190611e92565b838281518110610c8a57610c8a611f41565b6020908102919091010152600101610baa565b5060005b87811015610d2557610d1d898983818110610cbe57610cbe611f41565b9050604002016020016020810190610cd69190611e92565b60018b8b85818110610cea57610cea611f41565b610d009260206040909202019081019150611e92565b73ffffffffffffffffffffffffffffffffffffffff16919061133f565b600101610ca1565b508267ffffffffffffffff811115610d3f57610d3f611f12565b604051908082528060200260200182016040528015610d68578160200160208202803683370190505b50905060005b83811015610e0257610ddd858583818110610d8b57610d8b611f41565b9050602002810190610d9d91906121a8565b610dab906020810190611fd7565b878785818110610dbd57610dbd611f41565b9050602002810190610dcf91906121a8565b6105ca906020810190611e92565b828281518110610def57610def611f41565b6020908102919091010152600101610d6e565b50965096945050505050565b610e34604051806060016040528060001515815260200160608152602001600081525090565b6000803073ffffffffffffffffffffffffffffffffffffffff1663bcbef20660e01b8686604051602401610e699291906121dc565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529051610ef291906121f0565b600060405180830381855af49150503d8060008114610f2d576040519150601f19603f3d011682016040523d82523d6000602084013e610f32565b606091505b50915091508115610f9f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f5754463f2053686f756c642068617665206661696c656421000000000000000060448201526064016102c9565b60048101905080806020019051810190610fb9919061228a565b95945050505050565b610fed82827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6110d5565b5050565b6060611001848484611360611392565b949350505050565b600061101484611124565b90508060005b61102560018561203f565b8110156110ab57600061271086868481811061104357611043611f41565b9050604002016020013585611058919061237c565b6110629190612393565b9050611096878288888681811061107b5761107b611f41565b6110919260206040909202019081019150611e92565b6111dc565b6110a0818461203f565b92505060010161101a565b506110cd858286866110be60018261203f565b81811061107b5761107b611f41565b509392505050565b73ffffffffffffffffffffffffffffffffffffffff83161580159061110f575073ffffffffffffffffffffffffffffffffffffffff821615155b1561111f5761111f83838361133f565b505050565b600073ffffffffffffffffffffffffffffffffffffffff8216156111d5576040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8316906370a0823190602401602060405180830381865afa1580156111ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111d091906123ce565b610280565b4792915050565b811561111f5773ffffffffffffffffffffffffffffffffffffffff81166112005750335b73ffffffffffffffffffffffffffffffffffffffff831661123b5761111f73ffffffffffffffffffffffffffffffffffffffff821683611457565b61111f73ffffffffffffffffffffffffffffffffffffffff8416828461152d565b8415610ac7578673ffffffffffffffffffffffffffffffffffffffff1663edd9444b60405180606001604052808989808060200260200160405190810160405280939291908181526020016000905b828210156112d7576112c8604083028601368190038101906123e7565b815260200190600101906112ab565b50505050508152602001878152602001868152506112f589896115ae565b3386866040518663ffffffff1660e01b8152600401610a949594939291906124a3565b610fed82827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b61111f73ffffffffffffffffffffffffffffffffffffffff84168383611688565b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6060824710156113d0576040517fcd7860590000000000000000000000000000000000000000000000000000000081523060048201526024016102c9565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516113f991906121f0565b60006040518083038185875af1925050503d8060008114611436576040519150601f19603f3d011682016040523d82523d6000602084013e61143b565b606091505b509150915061144c87838387611766565b979650505050505050565b80471015611493576040517fcd7860590000000000000000000000000000000000000000000000000000000081523060048201526024016102c9565b60008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d80600081146114ed576040519150601f19603f3d011682016040523d82523d6000602084013e6114f2565b606091505b505090508061111f576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405173ffffffffffffffffffffffffffffffffffffffff83811660248301526044820183905261111f91859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506117f1565b60608167ffffffffffffffff8111156115c9576115c9611f12565b60405190808252806020026020018201604052801561160e57816020015b60408051808201909152600080825260208201528152602001906001900390816115e75790505b50905060005b815181101561043b5760405180604001604052803073ffffffffffffffffffffffffffffffffffffffff16815260200185858481811061165657611656611f41565b9050604002016020013581525082828151811061167557611675611f41565b6020908102919091010152600101611614565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b3000000000000000000000000000000000000000000000000000000001790526117148482611887565b6117605760405173ffffffffffffffffffffffffffffffffffffffff84811660248301526000604483015261175691869182169063095ea7b390606401611567565b61176084826117f1565b50505050565b606083156117e75782516000036117e0578473ffffffffffffffffffffffffffffffffffffffff163b6000036117e0576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff861660048201526024016102c9565b5081611001565b6110018383611944565b600061181373ffffffffffffffffffffffffffffffffffffffff841683611960565b905080516000141580156118385750808060200190518101906118369190612574565b155b1561111f576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841660048201526024016102c9565b60008060008473ffffffffffffffffffffffffffffffffffffffff16846040516118b191906121f0565b6000604051808303816000865af19150503d80600081146118ee576040519150601f19603f3d011682016040523d82523d6000602084013e6118f3565b606091505b509150915081801561191d57508051158061191d57508080602001905181019061191d9190612574565b8015610fb957505050505073ffffffffffffffffffffffffffffffffffffffff163b151590565b8151156119545781518083602001fd5b6113608163ffffffff16565b606061197183836000611360611392565b9392505050565b60006020828403121561198a57600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461197157600080fd5b60008083601f8401126119cc57600080fd5b50813567ffffffffffffffff8111156119e457600080fd5b6020830191508360208260061b85010111156119ff57600080fd5b9250929050565b60008083601f840112611a1857600080fd5b50813567ffffffffffffffff811115611a3057600080fd5b6020830191508360208260051b85010111156119ff57600080fd5b60008060008060008060008060a0898b031215611a6757600080fd5b883567ffffffffffffffff80821115611a7f57600080fd5b908a01906080828d031215611a9357600080fd5b90985060208a01359080821115611aa957600080fd5b611ab58c838d016119ba565b909950975060408b0135915080821115611ace57600080fd5b611ada8c838d01611a06565b909750955060608b0135915080821115611af357600080fd5b50611b008b828c01611a06565b999c989b50969995989497949560800135949350505050565b60005b83811015611b34578181015183820152602001611b1c565b50506000910152565b60008151808452611b55816020860160208601611b19565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000604082016040835280855180835260608501915060608160051b8601019250602080880160005b83811015611bfc577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0888703018552611bea868351611b3d565b95509382019390820190600101611bb0565b50508584038187015286518085528782019482019350915060005b82811015611c3357845184529381019392810192600101611c17565b5091979650505050505050565b60008060208385031215611c5357600080fd5b823567ffffffffffffffff811115611c6a57600080fd5b611c7685828601611a06565b90969095509350505050565b8051151582526000602082015160606020850152611ca36060850182611b3d565b604093840151949093019390935250919050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015611d2a577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452611d18858351611c82565b94509285019290850190600101611cde565b5092979650505050505050565b600060208284031215611d4957600080fd5b813567ffffffffffffffff811115611d6057600080fd5b8201610160818503121561197157600080fd5b600060208284031215611d8557600080fd5b813567ffffffffffffffff811115611d9c57600080fd5b8201610180818503121561197157600080fd5b60008060208385031215611dc257600080fd5b823567ffffffffffffffff80821115611dda57600080fd5b818501915085601f830112611dee57600080fd5b813581811115611dfd57600080fd5b866020828501011115611e0f57600080fd5b60209290920196919550909350505050565b60008060008060008060008060a0898b031215611e3d57600080fd5b883567ffffffffffffffff80821115611e5557600080fd5b908a01906060828d031215611a9357600080fd5b803573ffffffffffffffffffffffffffffffffffffffff81168114611e8d57600080fd5b919050565b600060208284031215611ea457600080fd5b61197182611e69565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112611ee257600080fd5b83018035915067ffffffffffffffff821115611efd57600080fd5b6020019150368190038213156119ff57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611fd057611fd0611f70565b5060010190565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261200c57600080fd5b83018035915067ffffffffffffffff82111561202757600080fd5b6020019150600681901b36038213156119ff57600080fd5b8181038181111561028057610280611f70565b8183823760009101908152919050565b6020815260006119716020830184611c82565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b60006101006120ee838951805173ffffffffffffffffffffffffffffffffffffffff168252602090810151910152565b602088015160408401526040880151606084015261212f6080840188805173ffffffffffffffffffffffffffffffffffffffff168252602090810151910152565b73ffffffffffffffffffffffffffffffffffffffff861660c08401528060e084015261215e8184018587612075565b98975050505050505050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa183360301811261219e57600080fd5b9190910192915050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc183360301811261219e57600080fd5b602081526000611001602083018486612075565b6000825161219e818460208701611b19565b6040516060810167ffffffffffffffff8111828210171561222557612225611f12565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561227257612272611f12565b604052919050565b80518015158114611e8d57600080fd5b6000602080838503121561229d57600080fd5b825167ffffffffffffffff808211156122b557600080fd5b90840190606082870312156122c957600080fd5b6122d1612202565b6122da8361227a565b815283830151828111156122ed57600080fd5b8301601f810188136122fe57600080fd5b80518381111561231057612310611f12565b612340867fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160161222b565b9350808452888682840101111561235657600080fd5b61236581878601888501611b19565b505092830152604090810151908201529392505050565b808202811582820484141761028057610280611f70565b6000826123c9577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000602082840312156123e057600080fd5b5051919050565b6000604082840312156123f957600080fd5b6040516040810181811067ffffffffffffffff8211171561241c5761241c611f12565b60405261242883611e69565b8152602083013560208201528091505092915050565b600081518084526020808501945080840160005b8381101561249857612485878351805173ffffffffffffffffffffffffffffffffffffffff168252602090810151910152565b6040969096019590820190600101612452565b509495945050505050565b60808152600060e082018751606060808501528181518084526101008601915060209350838301925060005b8181101561251557612502838551805173ffffffffffffffffffffffffffffffffffffffff168252602090810151910152565b92840192604092909201916001016124cf565b5050828a015160a086015260408a015160c08601528481038386015261253b818a61243e565b92505050612561604084018773ffffffffffffffffffffffffffffffffffffffff169052565b828103606084015261215e818587612075565b60006020828403121561258657600080fd5b6119718261227a56

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 Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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