ETH Price: $2,049.48 (+8.99%)

Contract

0xED306e38BB930ec9646FF3D917B2e513a97530b1

Overview

ETH Balance

0 ETH

ETH Value

$0.00
Transaction Hash
Method
Block
From
To
Sell Order Swap192318422025-01-17 16:58:4860 days ago1737133128IN
0xED306e38...3a97530b1
0.003333 ETH0.000135770.207
Sell Order Swap192073862025-01-16 18:34:5961 days ago1737052499IN
0xED306e38...3a97530b1
0.0419 ETH0.000026490.199
Sell Order Swap192073272025-01-16 18:31:4861 days ago1737052308IN
0xED306e38...3a97530b1
0.01 ETH0.000063840.17
Sell Order Swap191951912025-01-16 7:14:4362 days ago1737011683IN
0xED306e38...3a97530b1
0.0016 ETH0.000029480.0335
Sell Order Swap191119662025-01-12 22:33:2465 days ago1736721204IN
0xED306e38...3a97530b1
0.00415 ETH0.000023820.0362
Sell Order Swap190803492025-01-11 17:26:0266 days ago1736616362IN
0xED306e38...3a97530b1
0.004 ETH0.000031560.0492
Sell Order Swap190092322025-01-09 0:05:4769 days ago1736381147IN
0xED306e38...3a97530b1
0.007 ETH0.000070110.0875
Sell Order Swap187934342024-12-31 17:55:1577 days ago1735667715IN
0xED306e38...3a97530b1
0.0034 ETH0.000042420.171
Sell Order Swap187708842024-12-30 20:55:3378 days ago1735592133IN
0xED306e38...3a97530b1
0.012 ETH0.000100280.25949953
Sell Order Swap187131082024-12-28 15:33:2481 days ago1735400004IN
0xED306e38...3a97530b1
0 ETH0.000030620.0791
Sell Order Swap187130602024-12-28 15:30:4381 days ago1735399843IN
0xED306e38...3a97530b1
0 ETH0.000099210.082
Sell Order Swap184715192024-12-19 8:48:3690 days ago1734598116IN
0xED306e38...3a97530b1
0 ETH0.000070440.156
Sell Order Swap184711392024-12-19 8:27:2890 days ago1734596848IN
0xED306e38...3a97530b1
0 ETH0.00015460.156
Sell Order Swap183591562024-12-15 1:28:5894 days ago1734226138IN
0xED306e38...3a97530b1
0 ETH0.000091080.116
Buy Order Swap183590932024-12-15 1:25:2794 days ago1734225927IN
0xED306e38...3a97530b1
0 ETH0.000034140.113
Sell Order Swap183590662024-12-15 1:23:5594 days ago1734225835IN
0xED306e38...3a97530b1
0 ETH0.000117050.0957
Sell Order Swap183589172024-12-15 1:15:3894 days ago1734225338IN
0xED306e38...3a97530b1
0 ETH0.000012410.103
Sell Order Swap183425692024-12-14 10:09:1595 days ago1734170955IN
0xED306e38...3a97530b1
0 ETH0.000130680.14
Sell Order Swap182602212024-12-11 6:38:1698 days ago1733899096IN
0xED306e38...3a97530b1
0.00079 ETH0.000040640.159
Sell Order Swap182600902024-12-11 6:30:5898 days ago1733898658IN
0xED306e38...3a97530b1
0.0082 ETH0.000133720.148
Sell Order Swap182600692024-12-11 6:29:4898 days ago1733898588IN
0xED306e38...3a97530b1
0 ETH0.000124090.157
Sell Order Swap182598982024-12-11 6:20:2898 days ago1733898028IN
0xED306e38...3a97530b1
0 ETH0.000147990.156
Sell Order Swap182147882024-12-09 12:55:27100 days ago1733748927IN
0xED306e38...3a97530b1
0.0435 ETH0.000362520.595
Sell Order Swap182147322024-12-09 12:52:20100 days ago1733748740IN
0xED306e38...3a97530b1
0 ETH0.000615060.638
Sell Order Swap182144952024-12-09 12:39:26100 days ago1733747966IN
0xED306e38...3a97530b1
0.1344 ETH0.000304770.582

Latest 25 internal transactions (View All)

Parent Transaction Hash Block From To
192318422025-01-17 16:58:4860 days ago1737133128
0xED306e38...3a97530b1
0.003333 ETH
192073862025-01-16 18:34:5961 days ago1737052499
0xED306e38...3a97530b1
0.0419 ETH
192073272025-01-16 18:31:4861 days ago1737052308
0xED306e38...3a97530b1
0.01 ETH
191951912025-01-16 7:14:4362 days ago1737011683
0xED306e38...3a97530b1
0.0016 ETH
191119662025-01-12 22:33:2465 days ago1736721204
0xED306e38...3a97530b1
0.00415 ETH
190803492025-01-11 17:26:0266 days ago1736616362
0xED306e38...3a97530b1
0.004 ETH
190092322025-01-09 0:05:4769 days ago1736381147
0xED306e38...3a97530b1
0.007 ETH
187934342024-12-31 17:55:1577 days ago1735667715
0xED306e38...3a97530b1
0.0034 ETH
187708842024-12-30 20:55:3378 days ago1735592133
0xED306e38...3a97530b1
0.012 ETH
187131082024-12-28 15:33:2481 days ago1735400004
0xED306e38...3a97530b1
0.00507483 ETH
187131082024-12-28 15:33:2481 days ago1735400004
0xED306e38...3a97530b1
0.00507483 ETH
187130602024-12-28 15:30:4381 days ago1735399843
0xED306e38...3a97530b1
0.0066282 ETH
187130602024-12-28 15:30:4381 days ago1735399843
0xED306e38...3a97530b1
0.0066282 ETH
184715192024-12-19 8:48:3690 days ago1734598116
0xED306e38...3a97530b1
0.04278943 ETH
184715192024-12-19 8:48:3690 days ago1734598116
0xED306e38...3a97530b1
0.04278943 ETH
183591562024-12-15 1:28:5894 days ago1734226138
0xED306e38...3a97530b1
0.01142183 ETH
183591562024-12-15 1:28:5894 days ago1734226138
0xED306e38...3a97530b1
0.01142183 ETH
183590662024-12-15 1:23:5594 days ago1734225835
0xED306e38...3a97530b1
0.00298893 ETH
183590662024-12-15 1:23:5594 days ago1734225835
0xED306e38...3a97530b1
0.00298893 ETH
183589172024-12-15 1:15:3894 days ago1734225338
0xED306e38...3a97530b1
0.00195063 ETH
183589172024-12-15 1:15:3894 days ago1734225338
0xED306e38...3a97530b1
0.00195063 ETH
182602212024-12-11 6:38:1698 days ago1733899096
0xED306e38...3a97530b1
0.00079 ETH
182600902024-12-11 6:30:5898 days ago1733898658
0xED306e38...3a97530b1
0.0082 ETH
182600692024-12-11 6:29:4898 days ago1733898588
0xED306e38...3a97530b1
0.00351025 ETH
182600692024-12-11 6:29:4898 days ago1733898588
0xED306e38...3a97530b1
0.00351025 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
UniversalPermit2Adapter

Compiler Version
v0.8.22+commit.4fc1097e

Optimization Enabled:
Yes with 10000 runs

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  bytes4 private constant MAGIC_WORD = IERC1271.isValidSignature.selector;

  constructor(IPermit2 _permit2) {
    PERMIT2 = _permit2;
  }

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

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

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

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

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

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

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

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

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

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

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

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

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

    // Set amount in
    _amountIn = _params.amountIn;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  enum SwapType {
    Buy,
    Sell
  }

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

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

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

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

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

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

  struct SignatureTransferDetails {
    address to;
    uint256 requestedAmount;
  }

  function DOMAIN_SEPARATOR() external view returns (bytes32);

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

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

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

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

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

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

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

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

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

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

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

  address public constant NATIVE_TOKEN = address(0);

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

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

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

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

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

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

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

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

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

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

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

pragma solidity ^0.8.0;

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

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

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

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

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

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

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

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

pragma solidity ^0.8.0;

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 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.encodeWithSelector(token.transfer.selector, 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.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(IERC20 token, address spender, uint256 value) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 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);
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
        }
    }

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

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, 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);
        require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
    }

    /**
     * @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, "SafeERC20: low-level call failed");
        require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
    }

    /**
     * @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.isContract(address(token));
    }
}

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

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     *
     * Furthermore, `isContract` will also return true if the target contract within
     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
     * which only has an effect at the end of a transaction.
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @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 {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @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, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @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, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @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, "Address: low-level static call failed");
    }

    /**
     * @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,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @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, "Address: low-level delegate call failed");
    }

    /**
     * @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,
        string memory errorMessage
    ) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @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 one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // 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 {
            revert(errorMessage);
        }
    }
}

Settings
{
  "viaIR": false,
  "optimizer": {
    "runs": 10000,
    "enabled": true
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "none",
    "appendCBOR": false
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "libraries": {},
  "remappings": [
    "@mean-finance/oracles/=node_modules/@mean-finance/oracles/",
    "@mean-finance/nft-descriptors/=node_modules/@mean-finance/nft-descriptors/",
    "@mean-finance/call-simulation/contracts/=node_modules/@mean-finance/call-simulation/src/",
    "@mean-finance/swappers/=node_modules/@mean-finance/swappers/",
    "@mean-finance/dca-v2-core/=node_modules/@mean-finance/dca-v2-core/",
    "@mean-finance/permit2-adapter/=node_modules/@mean-finance/permit2-adapter/src/",
    "@mean-finance/transformers/=node_modules/@mean-finance/transformers/solidity/contracts/transformers/",
    "@mean-finance/dca-v2-periphery/=node_modules/@mean-finance/dca-v2-periphery/",
    "@mean-finance/uniswap-v3-oracle/=node_modules/@mean-finance/uniswap-v3-oracle/",
    "@call-simulation/=node_modules/@mean-finance/call-simulation/src/",
    "@chainlink/=node_modules/@chainlink/",
    "@openzeppelin/=node_modules/@openzeppelin/",
    "@api3/=node_modules/@api3/",
    "@uniswap/=node_modules/@uniswap/",
    "keep3r-v2/=node_modules/keep3r-v2/",
    "base64-sol/=node_modules/base64-sol/",
    "@sphinx-labs/contracts/=lib/sphinx/packages/contracts/contracts/foundry/",
    "forge-std/=lib/forge-std/src/",
    "@rari-capital/solmate/=lib/solmate/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "solmate/=lib/solmate/src/",
    "sphinx/=lib/sphinx/"
  ]
}

Contract Security Audit

Contract ABI

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

60a06040523480156200001157600080fd5b506040516200287838038062002878833981016040819052620000349162000046565b6001600160a01b031660805262000078565b6000602082840312156200005957600080fd5b81516001600160a01b03811681146200007157600080fd5b9392505050565b6080516127c8620000b0600039600081816101ef015281816102f2015281816103c80152818161086f015261105001526127c86000f3fe6080604052600436106100b55760003560e01c80634321431a11610069578063bcbef2061161004e578063bcbef20614610211578063ee4cfaf714610226578063ee8117211461023957600080fd5b80634321431a146101b55780636afdd850146101dd57600080fd5b80632c8aaabe1161009a5780632c8aaabe1461014757806331f7d964146101685780633ed242b41461019557600080fd5b806301ffc9a7146100c15780631626ba7e146100f657600080fd5b366100bc57005b600080fd5b3480156100cd57600080fd5b506100e16100dc366004611b3f565b61024c565b60405190151581526020015b60405180910390f35b34801561010257600080fd5b50610116610111366004611c32565b6102e5565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681526020016100ed565b61015a610155366004611d4d565b610347565b6040516100ed929190611e6b565b34801561017457600080fd5b5061017d600081565b6040516001600160a01b0390911681526020016100ed565b6101a86101a3366004611f24565b610413565b6040516100ed9190611f9b565b6101c86101c336600461201d565b6104eb565b604080519283526020830191909152016100ed565b3480156101e957600080fd5b5061017d7f000000000000000000000000000000000000000000000000000000000000000081565b61022461021f366004612059565b610735565b005b61015a6102343660046120cb565b6107fb565b6101c8610247366004612113565b61089a565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f3ed242b40000000000000000000000000000000000000000000000000000000014806102df57507fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000145b92915050565b6000336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461031e576000610340565b7f1626ba7e000000000000000000000000000000000000000000000000000000005b9392505050565b6060808280421115610393576040517f25f14a28000000000000000000000000000000000000000000000000000000008152426004820152602481018290526044015b60405180910390fd5b6103f36103a360208d018d61216b565b8c602001358d60400135878f80606001906103be9190612186565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016959493929190610ad9565b6104018a8a8a8a8a8a610ba2565b92509250509850989650505050505050565b60608167ffffffffffffffff81111561042e5761042e611b81565b60405190808252806020026020018201604052801561048557816020015b610472604051806060016040528060001515815260200160608152602001600081525090565b81526020019060019003908161044c5790505b50905060005b828110156104e4576104bf8484838181106104a8576104a86121eb565b90506020028101906104ba9190612186565b610e94565b8282815181106104d1576104d16121eb565b602090810291909101015260010161048b565b5092915050565b600080823542811015610533576040517f25f14a280000000000000000000000000000000000000000000000000000000081524260048201526024810182905260440161038a565b61055f610546604086016020870161216b565b6040860135606087013587356103be60808a018a612186565b61059161057260c0860160a0870161216b565b610582604087016020880161216b565b6001600160a01b03169061101d565b6000806105a4604087016020880161216b565b6001600160a01b0316146105b95760006105bf565b84604001355b90506105e76105d460e0870160c0880161216b565b6105e160e0880188612186565b8461104c565b5061061b6105f961014087018761221a565b61060b61012089016101008a0161216b565b6001600160a01b0316919061110f565b925084610120013583101561066a576040517f763dfca000000000000000000000000000000000000000000000000000000000815260048101849052610120860135602482015260440161038a565b61069f61067d60c0870160a0880161216b565b600161068f6040890160208a0161216b565b6001600160a01b031691906111db565b60408501803594507ff186b619e99ec011dd2df76f232917ce8326af9997ad34223335e401e95536f29033906001906106db9060208a0161216b565b6106ed6101208a016101008b0161216b565b60408a01358861070360e08d0160c08e0161216b565b6107116101608e018e612186565b604051610726999897969594939291906122ad565b60405180910390a15050915091565b60005a9050600080306001600160a01b03168585604051610757929190612344565b600060405180830381855af49150503d8060008114610792576040519150601f19603f3d011682016040523d82523d6000602084013e610797565b606091505b509150915060005a6107a99085612383565b905060405180606001604052808415158152602001838152602001828152506040517f493703af00000000000000000000000000000000000000000000000000000000815260040161038a9190612396565b6060808280421115610842576040517f25f14a280000000000000000000000000000000000000000000000000000000081524260048201526024810182905260440161038a565b6103f361084f8c8061221a565b8d60200135878f80604001906108659190612186565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016959493929190611210565b6000808235428110156108e2576040517f25f14a280000000000000000000000000000000000000000000000000000000081524260048201526024810182905260440161038a565b6108f5610546604086016020870161216b565b61090861057260c0860160a0870161216b565b60008061091b604087016020880161216b565b6001600160a01b031614610930576000610936565b84604001355b905061094b6105d460e0870160c0880161216b565b50600061096f610961604088016020890161216b565b6001600160a01b03166112bf565b905061099461098261014088018861221a565b61060b6101208a016101008b0161216b565b93508561012001358410156109e3576040517f763dfca000000000000000000000000000000000000000000000000000000000815260048101859052610120870135602482015260440161038a565b610a19816109f961018089016101608a0161216b565b610a0960408a0160208b0161216b565b6001600160a01b0316919061135d565b610a3e610a2c60c0880160a0890161216b565b600161068f60408a0160208b0161216b565b610a4c816040880135612383565b94507ff186b619e99ec011dd2df76f232917ce8326af9997ad34223335e401e95536f2336000610a8260408a0160208b0161216b565b610a946101208b016101008c0161216b565b8989610aa660e08e0160c08f0161216b565b610ab46101808f018f612186565b604051610ac9999897969594939291906122ad565b60405180910390a1505050915091565b8015610b99576040805160a0810182526001600160a01b038881166060830190815260808301899052825260208083018890528284018790528351808501855230815290810189905292517f30f28b7a000000000000000000000000000000000000000000000000000000008152908a16926330f28b7a92610b66929091903390889088906004016123a9565b600060405180830381600087803b158015610b8057600080fd5b505af1158015610b94573d6000803e3d6000fd5b505050505b50505050505050565b60608060005b87811015610c1c57610c14898983818110610bc557610bc56121eb565b9050604002016020016020810190610bdd919061216b565b8a8a84818110610bef57610bef6121eb565b610c05926020604090920201908101915061216b565b6001600160a01b0316906113a9565b600101610ba8565b508467ffffffffffffffff811115610c3657610c36611b81565b604051908082528060200260200182016040528015610c6957816020015b6060815260200190600190039081610c545790505b50915060005b85811015610d3057610d0b878783818110610c8c57610c8c6121eb565b9050602002810190610c9e919061242e565b610cac90602081019061216b565b888884818110610cbe57610cbe6121eb565b9050602002810190610cd0919061242e565b610cde906020810190612186565b8a8a86818110610cf057610cf06121eb565b9050602002810190610d02919061242e565b6040013561104c565b838281518110610d1d57610d1d6121eb565b6020908102919091010152600101610c6f565b5060005b87811015610dab57610da3898983818110610d5157610d516121eb565b9050604002016020016020810190610d69919061216b565b60018b8b85818110610d7d57610d7d6121eb565b610d93926020604090920201908101915061216b565b6001600160a01b031691906113d0565b600101610d34565b508267ffffffffffffffff811115610dc557610dc5611b81565b604051908082528060200260200182016040528015610dee578160200160208202803683370190505b50905060005b83811015610e8857610e63858583818110610e1157610e116121eb565b9050602002810190610e23919061246c565b610e3190602081019061221a565b878785818110610e4357610e436121eb565b9050602002810190610e55919061246c565b61060b90602081019061216b565b828281518110610e7557610e756121eb565b6020908102919091010152600101610df4565b50965096945050505050565b610eba604051806060016040528060001515815260200160608152602001600081525090565b600080306001600160a01b031663bcbef20660e01b8686604051602401610ee29291906124a0565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529051610f4d91906124b4565b600060405180830381855af49150503d8060008114610f88576040519150601f19603f3d011682016040523d82523d6000602084013e610f8d565b606091505b50915091508115610ffa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f5754463f2053686f756c642068617665206661696c6564210000000000000000604482015260640161038a565b6004810190508080602001905181019061101491906124d6565b95945050505050565b61104882827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6111db565b5050565b60607f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316856001600160a01b0316036110b9576040517fe0d7940800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61110484848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050506001600160a01b038816919050846113e4565b90505b949350505050565b600061111a846112bf565b90508060005b61112b600185612383565b8110156111b1576000612710868684818110611149576111496121eb565b905060400201602001358561115e919061259b565b61116891906125b2565b905061119c8782888886818110611181576111816121eb565b611197926020604090920201908101915061216b565b61135d565b6111a68184612383565b925050600101611120565b506111d3858286866111c4600182612383565b818110611181576111816121eb565b509392505050565b6001600160a01b038316158015906111fb57506001600160a01b03821615155b1561120b5761120b8383836113d0565b505050565b8415610b9957866001600160a01b031663edd9444b60405180606001604052808989808060200260200160405190810160405280939291908181526020016000905b8282101561127e5761126f604083028601368190038101906125ed565b81526020019060010190611252565b505050505081526020018781526020018681525061129c898961140a565b3386866040518663ffffffff1660e01b8152600401610b6695949392919061269d565b60006001600160a01b03821615611356576040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa15801561132d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113519190612757565b6102df565b4792915050565b811561120b576001600160a01b0381166113745750335b6001600160a01b0383166113955761120b6001600160a01b038216836114d7565b61120b6001600160a01b0384168284611624565b61104882827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b61120b6001600160a01b03841683836116cd565b606061110784848460405180606001604052806029815260200161279f602991396117a9565b60608167ffffffffffffffff81111561142557611425611b81565b60405190808252806020026020018201604052801561146a57816020015b60408051808201909152600080825260208201528152602001906001900390816114435790505b50905060005b81518110156104e4576040518060400160405280306001600160a01b031681526020018585848181106114a5576114a56121eb565b905060400201602001358152508282815181106114c4576114c46121eb565b6020908102919091010152600101611470565b80471015611541576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e6365000000604482015260640161038a565b6000826001600160a01b03168260405160006040518083038185875af1925050503d806000811461158e576040519150601f19603f3d011682016040523d82523d6000602084013e611593565b606091505b505090508061120b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d61792068617665207265766572746564000000000000606482015260840161038a565b6040516001600160a01b03831660248201526044810182905261120b9084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526118b5565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b30000000000000000000000000000000000000000000000000000000017905261174c84826119b7565b6117a3576040516001600160a01b0384166024820152600060448201526117999085907f095ea7b30000000000000000000000000000000000000000000000000000000090606401611669565b6117a384826118b5565b50505050565b60608247101561183b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c0000000000000000000000000000000000000000000000000000606482015260840161038a565b600080866001600160a01b0316858760405161185791906124b4565b60006040518083038185875af1925050503d8060008114611894576040519150601f19603f3d011682016040523d82523d6000602084013e611899565b606091505b50915091506118aa87838387611a59565b979650505050505050565b600061190a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611aec9092919063ffffffff16565b905080516000148061192b57508080602001905181019061192b9190612770565b61120b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840161038a565b6000806000846001600160a01b0316846040516119d491906124b4565b6000604051808303816000865af19150503d8060008114611a11576040519150601f19603f3d011682016040523d82523d6000602084013e611a16565b606091505b5091509150818015611a40575080511580611a40575080806020019051810190611a409190612770565b801561101457506001600160a01b0385163b1515611014565b60608315611ae2578251600003611adb576001600160a01b0385163b611adb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161038a565b5081611107565b6111078383611afb565b606061110784846000856117a9565b815115611b0b5781518083602001fd5b806040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161038a919061278b565b600060208284031215611b5157600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461034057600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516060810167ffffffffffffffff81118282101715611bd357611bd3611b81565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715611c0257611c02611b81565b604052919050565b600067ffffffffffffffff821115611c2457611c24611b81565b50601f01601f191660200190565b60008060408385031215611c4557600080fd5b82359150602083013567ffffffffffffffff811115611c6357600080fd5b8301601f81018513611c7457600080fd5b8035611c87611c8282611c0a565b611bd9565b818152866020838501011115611c9c57600080fd5b816020840160208301376000602083830101528093505050509250929050565b60008083601f840112611cce57600080fd5b50813567ffffffffffffffff811115611ce657600080fd5b6020830191508360208260061b8501011115611d0157600080fd5b9250929050565b60008083601f840112611d1a57600080fd5b50813567ffffffffffffffff811115611d3257600080fd5b6020830191508360208260051b8501011115611d0157600080fd5b60008060008060008060008060a0898b031215611d6957600080fd5b883567ffffffffffffffff80821115611d8157600080fd5b908a01906080828d031215611d9557600080fd5b90985060208a01359080821115611dab57600080fd5b611db78c838d01611cbc565b909950975060408b0135915080821115611dd057600080fd5b611ddc8c838d01611d08565b909750955060608b0135915080821115611df557600080fd5b50611e028b828c01611d08565b999c989b50969995989497949560800135949350505050565b60005b83811015611e36578181015183820152602001611e1e565b50506000910152565b60008151808452611e57816020860160208601611e1b565b601f01601f19169290920160200192915050565b6000604082016040835280855180835260608501915060608160051b8601019250602080880160005b83811015611ee0577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0888703018552611ece868351611e3f565b95509382019390820190600101611e94565b50508584038187015286518085528782019482019350915060005b82811015611f1757845184529381019392810192600101611efb565b5091979650505050505050565b60008060208385031215611f3757600080fd5b823567ffffffffffffffff811115611f4e57600080fd5b611f5a85828601611d08565b90969095509350505050565b8051151582526000602082015160606020850152611f876060850182611e3f565b604093840151949093019390935250919050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b82811015612010577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452611ffe858351611f66565b94509285019290850190600101611fc4565b5092979650505050505050565b60006020828403121561202f57600080fd5b813567ffffffffffffffff81111561204657600080fd5b8201610180818503121561034057600080fd5b6000806020838503121561206c57600080fd5b823567ffffffffffffffff8082111561208457600080fd5b818501915085601f83011261209857600080fd5b8135818111156120a757600080fd5b8660208285010111156120b957600080fd5b60209290920196919550909350505050565b60008060008060008060008060a0898b0312156120e757600080fd5b883567ffffffffffffffff808211156120ff57600080fd5b908a01906060828d031215611d9557600080fd5b60006020828403121561212557600080fd5b813567ffffffffffffffff81111561213c57600080fd5b82016101a0818503121561034057600080fd5b80356001600160a01b038116811461216657600080fd5b919050565b60006020828403121561217d57600080fd5b6103408261214f565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126121bb57600080fd5b83018035915067ffffffffffffffff8211156121d657600080fd5b602001915036819003821315611d0157600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261224f57600080fd5b83018035915067ffffffffffffffff82111561226a57600080fd5b6020019150600681901b3603821315611d0157600080fd5b818352818160208501375060006020828401015260006020601f19601f840116840101905092915050565b60006101006001600160a01b03808d16845260028c106122f6577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8b6020850152808b166040850152808a1660608501528860808501528760a085015280871660c0850152508060e08401526123348184018587612282565b9c9b505050505050505050505050565b8183823760009101908152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b818103818111156102df576102df612354565b6020815260006103406020830184611f66565b60006101006123cc83895180516001600160a01b03168252602090810151910152565b6020880151604084015260408801516060840152612400608084018880516001600160a01b03168252602090810151910152565b6001600160a01b03861660c08401528060e08401526124228184018587612282565b98975050505050505050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa183360301811261246257600080fd5b9190910192915050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc183360301811261246257600080fd5b602081526000611107602083018486612282565b60008251612462818460208701611e1b565b8051801515811461216657600080fd5b600060208083850312156124e957600080fd5b825167ffffffffffffffff8082111561250157600080fd5b908401906060828703121561251557600080fd5b61251d611bb0565b612526836124c6565b8152838301518281111561253957600080fd5b83019150601f8201871361254c57600080fd5b815161255a611c8282611c0a565b818152888683860101111561256e57600080fd5b61257d82878301888701611e1b565b80868401525050604083015160408201528094505050505092915050565b80820281158282048414176102df576102df612354565b6000826125e8577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000604082840312156125ff57600080fd5b6040516040810181811067ffffffffffffffff8211171561262257612622611b81565b60405261262e8361214f565b8152602083013560208201528091505092915050565b60008151808452602080850194506020840160005b838110156126925761267f87835180516001600160a01b03168252602090810151910152565b6040969096019590820190600101612659565b509495945050505050565b60808152600060e08201875160606080850152818151808452610100860191506020935060208301925060005b81811015612703576126f083855180516001600160a01b03168252602090810151910152565b92840192604092909201916001016126ca565b505060208a015160a086015260408a015160c0860152848103602086015261272b818a612644565b9250505061274460408401876001600160a01b03169052565b8281036060840152612422818587612282565b60006020828403121561276957600080fd5b5051919050565b60006020828403121561278257600080fd5b610340826124c6565b6020815260006103406020830184611e3f56fe416464726573733a206c6f772d6c6576656c2063616c6c20776974682076616c7565206661696c6564000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3000000000000000000000000bc2122028eecd61df4b2cb2b996c00bd856e333b00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000001000000000000000000000000bc2122028eecd61df4b2cb2b996c00bd856e333b

Deployed Bytecode

0x6080604052600436106100b55760003560e01c80634321431a11610069578063bcbef2061161004e578063bcbef20614610211578063ee4cfaf714610226578063ee8117211461023957600080fd5b80634321431a146101b55780636afdd850146101dd57600080fd5b80632c8aaabe1161009a5780632c8aaabe1461014757806331f7d964146101685780633ed242b41461019557600080fd5b806301ffc9a7146100c15780631626ba7e146100f657600080fd5b366100bc57005b600080fd5b3480156100cd57600080fd5b506100e16100dc366004611b3f565b61024c565b60405190151581526020015b60405180910390f35b34801561010257600080fd5b50610116610111366004611c32565b6102e5565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681526020016100ed565b61015a610155366004611d4d565b610347565b6040516100ed929190611e6b565b34801561017457600080fd5b5061017d600081565b6040516001600160a01b0390911681526020016100ed565b6101a86101a3366004611f24565b610413565b6040516100ed9190611f9b565b6101c86101c336600461201d565b6104eb565b604080519283526020830191909152016100ed565b3480156101e957600080fd5b5061017d7f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba381565b61022461021f366004612059565b610735565b005b61015a6102343660046120cb565b6107fb565b6101c8610247366004612113565b61089a565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f3ed242b40000000000000000000000000000000000000000000000000000000014806102df57507fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000145b92915050565b6000336001600160a01b037f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3161461031e576000610340565b7f1626ba7e000000000000000000000000000000000000000000000000000000005b9392505050565b6060808280421115610393576040517f25f14a28000000000000000000000000000000000000000000000000000000008152426004820152602481018290526044015b60405180910390fd5b6103f36103a360208d018d61216b565b8c602001358d60400135878f80606001906103be9190612186565b6001600160a01b037f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba316959493929190610ad9565b6104018a8a8a8a8a8a610ba2565b92509250509850989650505050505050565b60608167ffffffffffffffff81111561042e5761042e611b81565b60405190808252806020026020018201604052801561048557816020015b610472604051806060016040528060001515815260200160608152602001600081525090565b81526020019060019003908161044c5790505b50905060005b828110156104e4576104bf8484838181106104a8576104a86121eb565b90506020028101906104ba9190612186565b610e94565b8282815181106104d1576104d16121eb565b602090810291909101015260010161048b565b5092915050565b600080823542811015610533576040517f25f14a280000000000000000000000000000000000000000000000000000000081524260048201526024810182905260440161038a565b61055f610546604086016020870161216b565b6040860135606087013587356103be60808a018a612186565b61059161057260c0860160a0870161216b565b610582604087016020880161216b565b6001600160a01b03169061101d565b6000806105a4604087016020880161216b565b6001600160a01b0316146105b95760006105bf565b84604001355b90506105e76105d460e0870160c0880161216b565b6105e160e0880188612186565b8461104c565b5061061b6105f961014087018761221a565b61060b61012089016101008a0161216b565b6001600160a01b0316919061110f565b925084610120013583101561066a576040517f763dfca000000000000000000000000000000000000000000000000000000000815260048101849052610120860135602482015260440161038a565b61069f61067d60c0870160a0880161216b565b600161068f6040890160208a0161216b565b6001600160a01b031691906111db565b60408501803594507ff186b619e99ec011dd2df76f232917ce8326af9997ad34223335e401e95536f29033906001906106db9060208a0161216b565b6106ed6101208a016101008b0161216b565b60408a01358861070360e08d0160c08e0161216b565b6107116101608e018e612186565b604051610726999897969594939291906122ad565b60405180910390a15050915091565b60005a9050600080306001600160a01b03168585604051610757929190612344565b600060405180830381855af49150503d8060008114610792576040519150601f19603f3d011682016040523d82523d6000602084013e610797565b606091505b509150915060005a6107a99085612383565b905060405180606001604052808415158152602001838152602001828152506040517f493703af00000000000000000000000000000000000000000000000000000000815260040161038a9190612396565b6060808280421115610842576040517f25f14a280000000000000000000000000000000000000000000000000000000081524260048201526024810182905260440161038a565b6103f361084f8c8061221a565b8d60200135878f80604001906108659190612186565b6001600160a01b037f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba316959493929190611210565b6000808235428110156108e2576040517f25f14a280000000000000000000000000000000000000000000000000000000081524260048201526024810182905260440161038a565b6108f5610546604086016020870161216b565b61090861057260c0860160a0870161216b565b60008061091b604087016020880161216b565b6001600160a01b031614610930576000610936565b84604001355b905061094b6105d460e0870160c0880161216b565b50600061096f610961604088016020890161216b565b6001600160a01b03166112bf565b905061099461098261014088018861221a565b61060b6101208a016101008b0161216b565b93508561012001358410156109e3576040517f763dfca000000000000000000000000000000000000000000000000000000000815260048101859052610120870135602482015260440161038a565b610a19816109f961018089016101608a0161216b565b610a0960408a0160208b0161216b565b6001600160a01b0316919061135d565b610a3e610a2c60c0880160a0890161216b565b600161068f60408a0160208b0161216b565b610a4c816040880135612383565b94507ff186b619e99ec011dd2df76f232917ce8326af9997ad34223335e401e95536f2336000610a8260408a0160208b0161216b565b610a946101208b016101008c0161216b565b8989610aa660e08e0160c08f0161216b565b610ab46101808f018f612186565b604051610ac9999897969594939291906122ad565b60405180910390a1505050915091565b8015610b99576040805160a0810182526001600160a01b038881166060830190815260808301899052825260208083018890528284018790528351808501855230815290810189905292517f30f28b7a000000000000000000000000000000000000000000000000000000008152908a16926330f28b7a92610b66929091903390889088906004016123a9565b600060405180830381600087803b158015610b8057600080fd5b505af1158015610b94573d6000803e3d6000fd5b505050505b50505050505050565b60608060005b87811015610c1c57610c14898983818110610bc557610bc56121eb565b9050604002016020016020810190610bdd919061216b565b8a8a84818110610bef57610bef6121eb565b610c05926020604090920201908101915061216b565b6001600160a01b0316906113a9565b600101610ba8565b508467ffffffffffffffff811115610c3657610c36611b81565b604051908082528060200260200182016040528015610c6957816020015b6060815260200190600190039081610c545790505b50915060005b85811015610d3057610d0b878783818110610c8c57610c8c6121eb565b9050602002810190610c9e919061242e565b610cac90602081019061216b565b888884818110610cbe57610cbe6121eb565b9050602002810190610cd0919061242e565b610cde906020810190612186565b8a8a86818110610cf057610cf06121eb565b9050602002810190610d02919061242e565b6040013561104c565b838281518110610d1d57610d1d6121eb565b6020908102919091010152600101610c6f565b5060005b87811015610dab57610da3898983818110610d5157610d516121eb565b9050604002016020016020810190610d69919061216b565b60018b8b85818110610d7d57610d7d6121eb565b610d93926020604090920201908101915061216b565b6001600160a01b031691906113d0565b600101610d34565b508267ffffffffffffffff811115610dc557610dc5611b81565b604051908082528060200260200182016040528015610dee578160200160208202803683370190505b50905060005b83811015610e8857610e63858583818110610e1157610e116121eb565b9050602002810190610e23919061246c565b610e3190602081019061221a565b878785818110610e4357610e436121eb565b9050602002810190610e55919061246c565b61060b90602081019061216b565b828281518110610e7557610e756121eb565b6020908102919091010152600101610df4565b50965096945050505050565b610eba604051806060016040528060001515815260200160608152602001600081525090565b600080306001600160a01b031663bcbef20660e01b8686604051602401610ee29291906124a0565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529051610f4d91906124b4565b600060405180830381855af49150503d8060008114610f88576040519150601f19603f3d011682016040523d82523d6000602084013e610f8d565b606091505b50915091508115610ffa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f5754463f2053686f756c642068617665206661696c6564210000000000000000604482015260640161038a565b6004810190508080602001905181019061101491906124d6565b95945050505050565b61104882827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6111db565b5050565b60607f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba36001600160a01b0316856001600160a01b0316036110b9576040517fe0d7940800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61110484848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050506001600160a01b038816919050846113e4565b90505b949350505050565b600061111a846112bf565b90508060005b61112b600185612383565b8110156111b1576000612710868684818110611149576111496121eb565b905060400201602001358561115e919061259b565b61116891906125b2565b905061119c8782888886818110611181576111816121eb565b611197926020604090920201908101915061216b565b61135d565b6111a68184612383565b925050600101611120565b506111d3858286866111c4600182612383565b818110611181576111816121eb565b509392505050565b6001600160a01b038316158015906111fb57506001600160a01b03821615155b1561120b5761120b8383836113d0565b505050565b8415610b9957866001600160a01b031663edd9444b60405180606001604052808989808060200260200160405190810160405280939291908181526020016000905b8282101561127e5761126f604083028601368190038101906125ed565b81526020019060010190611252565b505050505081526020018781526020018681525061129c898961140a565b3386866040518663ffffffff1660e01b8152600401610b6695949392919061269d565b60006001600160a01b03821615611356576040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa15801561132d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113519190612757565b6102df565b4792915050565b811561120b576001600160a01b0381166113745750335b6001600160a01b0383166113955761120b6001600160a01b038216836114d7565b61120b6001600160a01b0384168284611624565b61104882827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b61120b6001600160a01b03841683836116cd565b606061110784848460405180606001604052806029815260200161279f602991396117a9565b60608167ffffffffffffffff81111561142557611425611b81565b60405190808252806020026020018201604052801561146a57816020015b60408051808201909152600080825260208201528152602001906001900390816114435790505b50905060005b81518110156104e4576040518060400160405280306001600160a01b031681526020018585848181106114a5576114a56121eb565b905060400201602001358152508282815181106114c4576114c46121eb565b6020908102919091010152600101611470565b80471015611541576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e6365000000604482015260640161038a565b6000826001600160a01b03168260405160006040518083038185875af1925050503d806000811461158e576040519150601f19603f3d011682016040523d82523d6000602084013e611593565b606091505b505090508061120b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d61792068617665207265766572746564000000000000606482015260840161038a565b6040516001600160a01b03831660248201526044810182905261120b9084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526118b5565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b30000000000000000000000000000000000000000000000000000000017905261174c84826119b7565b6117a3576040516001600160a01b0384166024820152600060448201526117999085907f095ea7b30000000000000000000000000000000000000000000000000000000090606401611669565b6117a384826118b5565b50505050565b60608247101561183b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c0000000000000000000000000000000000000000000000000000606482015260840161038a565b600080866001600160a01b0316858760405161185791906124b4565b60006040518083038185875af1925050503d8060008114611894576040519150601f19603f3d011682016040523d82523d6000602084013e611899565b606091505b50915091506118aa87838387611a59565b979650505050505050565b600061190a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611aec9092919063ffffffff16565b905080516000148061192b57508080602001905181019061192b9190612770565b61120b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840161038a565b6000806000846001600160a01b0316846040516119d491906124b4565b6000604051808303816000865af19150503d8060008114611a11576040519150601f19603f3d011682016040523d82523d6000602084013e611a16565b606091505b5091509150818015611a40575080511580611a40575080806020019051810190611a409190612770565b801561101457506001600160a01b0385163b1515611014565b60608315611ae2578251600003611adb576001600160a01b0385163b611adb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161038a565b5081611107565b6111078383611afb565b606061110784846000856117a9565b815115611b0b5781518083602001fd5b806040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161038a919061278b565b600060208284031215611b5157600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461034057600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516060810167ffffffffffffffff81118282101715611bd357611bd3611b81565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715611c0257611c02611b81565b604052919050565b600067ffffffffffffffff821115611c2457611c24611b81565b50601f01601f191660200190565b60008060408385031215611c4557600080fd5b82359150602083013567ffffffffffffffff811115611c6357600080fd5b8301601f81018513611c7457600080fd5b8035611c87611c8282611c0a565b611bd9565b818152866020838501011115611c9c57600080fd5b816020840160208301376000602083830101528093505050509250929050565b60008083601f840112611cce57600080fd5b50813567ffffffffffffffff811115611ce657600080fd5b6020830191508360208260061b8501011115611d0157600080fd5b9250929050565b60008083601f840112611d1a57600080fd5b50813567ffffffffffffffff811115611d3257600080fd5b6020830191508360208260051b8501011115611d0157600080fd5b60008060008060008060008060a0898b031215611d6957600080fd5b883567ffffffffffffffff80821115611d8157600080fd5b908a01906080828d031215611d9557600080fd5b90985060208a01359080821115611dab57600080fd5b611db78c838d01611cbc565b909950975060408b0135915080821115611dd057600080fd5b611ddc8c838d01611d08565b909750955060608b0135915080821115611df557600080fd5b50611e028b828c01611d08565b999c989b50969995989497949560800135949350505050565b60005b83811015611e36578181015183820152602001611e1e565b50506000910152565b60008151808452611e57816020860160208601611e1b565b601f01601f19169290920160200192915050565b6000604082016040835280855180835260608501915060608160051b8601019250602080880160005b83811015611ee0577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0888703018552611ece868351611e3f565b95509382019390820190600101611e94565b50508584038187015286518085528782019482019350915060005b82811015611f1757845184529381019392810192600101611efb565b5091979650505050505050565b60008060208385031215611f3757600080fd5b823567ffffffffffffffff811115611f4e57600080fd5b611f5a85828601611d08565b90969095509350505050565b8051151582526000602082015160606020850152611f876060850182611e3f565b604093840151949093019390935250919050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b82811015612010577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452611ffe858351611f66565b94509285019290850190600101611fc4565b5092979650505050505050565b60006020828403121561202f57600080fd5b813567ffffffffffffffff81111561204657600080fd5b8201610180818503121561034057600080fd5b6000806020838503121561206c57600080fd5b823567ffffffffffffffff8082111561208457600080fd5b818501915085601f83011261209857600080fd5b8135818111156120a757600080fd5b8660208285010111156120b957600080fd5b60209290920196919550909350505050565b60008060008060008060008060a0898b0312156120e757600080fd5b883567ffffffffffffffff808211156120ff57600080fd5b908a01906060828d031215611d9557600080fd5b60006020828403121561212557600080fd5b813567ffffffffffffffff81111561213c57600080fd5b82016101a0818503121561034057600080fd5b80356001600160a01b038116811461216657600080fd5b919050565b60006020828403121561217d57600080fd5b6103408261214f565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126121bb57600080fd5b83018035915067ffffffffffffffff8211156121d657600080fd5b602001915036819003821315611d0157600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261224f57600080fd5b83018035915067ffffffffffffffff82111561226a57600080fd5b6020019150600681901b3603821315611d0157600080fd5b818352818160208501375060006020828401015260006020601f19601f840116840101905092915050565b60006101006001600160a01b03808d16845260028c106122f6577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8b6020850152808b166040850152808a1660608501528860808501528760a085015280871660c0850152508060e08401526123348184018587612282565b9c9b505050505050505050505050565b8183823760009101908152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b818103818111156102df576102df612354565b6020815260006103406020830184611f66565b60006101006123cc83895180516001600160a01b03168252602090810151910152565b6020880151604084015260408801516060840152612400608084018880516001600160a01b03168252602090810151910152565b6001600160a01b03861660c08401528060e08401526124228184018587612282565b98975050505050505050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa183360301811261246257600080fd5b9190910192915050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc183360301811261246257600080fd5b602081526000611107602083018486612282565b60008251612462818460208701611e1b565b8051801515811461216657600080fd5b600060208083850312156124e957600080fd5b825167ffffffffffffffff8082111561250157600080fd5b908401906060828703121561251557600080fd5b61251d611bb0565b612526836124c6565b8152838301518281111561253957600080fd5b83019150601f8201871361254c57600080fd5b815161255a611c8282611c0a565b818152888683860101111561256e57600080fd5b61257d82878301888701611e1b565b80868401525050604083015160408201528094505050505092915050565b80820281158282048414176102df576102df612354565b6000826125e8577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000604082840312156125ff57600080fd5b6040516040810181811067ffffffffffffffff8211171561262257612622611b81565b60405261262e8361214f565b8152602083013560208201528091505092915050565b60008151808452602080850194506020840160005b838110156126925761267f87835180516001600160a01b03168252602090810151910152565b6040969096019590820190600101612659565b509495945050505050565b60808152600060e08201875160606080850152818151808452610100860191506020935060208301925060005b81811015612703576126f083855180516001600160a01b03168252602090810151910152565b92840192604092909201916001016126ca565b505060208a015160a086015260408a015160c0860152848103602086015261272b818a612644565b9250505061274460408401876001600160a01b03169052565b8281036060840152612422818587612282565b60006020828403121561276957600080fd5b5051919050565b60006020828403121561278257600080fd5b610340826124c6565b6020815260006103406020830184611e3f56fe416464726573733a206c6f772d6c6576656c2063616c6c20776974682076616c7565206661696c6564

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

000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3000000000000000000000000bc2122028eecd61df4b2cb2b996c00bd856e333b00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000001000000000000000000000000bc2122028eecd61df4b2cb2b996c00bd856e333b

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

-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3
Arg [1] : 000000000000000000000000bc2122028eecd61df4b2cb2b996c00bd856e333b
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000060
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [4] : 000000000000000000000000bc2122028eecd61df4b2cb2b996c00bd856e333b


Block Transaction Gas Used Reward
view all blocks sequenced

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

Validator Index Block Amount
View All Withdrawals

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

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