ETH Price: $2,996.15 (-6.96%)

Contract

0x91456757198FA14b9fA23f265Eee8Ee8AFfDdbc2
 

Overview

ETH Balance

0 ETH

ETH Value

$0.00

Sponsored

Transaction Hash
Method
Block
From
To
Value
Execute Order1131158342023-12-06 2:40:45129 days ago1701830445IN
0x91456757...8AFfDdbc2
0 ETH0.000004850.00871006
Execute Order1130929992023-12-05 13:59:35130 days ago1701784775IN
0x91456757...8AFfDdbc2
0.013 ETH0.000013030.00935753
Execute Order1130929672023-12-05 13:58:31130 days ago1701784711IN
0x91456757...8AFfDdbc2
0.01 ETH0.000012830.00972662
Execute Order1130929212023-12-05 13:56:59130 days ago1701784619IN
0x91456757...8AFfDdbc2
0 ETH0.000015260.00989751
Execute Order1130926252023-12-05 13:47:07130 days ago1701784027IN
0x91456757...8AFfDdbc2
0 ETH0.000015520.00945833
Execute Order1130925222023-12-05 13:43:41130 days ago1701783821IN
0x91456757...8AFfDdbc2
0 ETH0.000015310.0161603
Execute Order1130924152023-12-05 13:40:07130 days ago1701783607IN
0x91456757...8AFfDdbc2
0 ETH0.000240330.110534
Execute Order1130923792023-12-05 13:38:55130 days ago1701783535IN
0x91456757...8AFfDdbc2
0 ETH0.000158730.110534
Execute Order1130889752023-12-05 11:45:27130 days ago1701776727IN
0x91456757...8AFfDdbc2
0 ETH0.000006690.0088304
Execute Order1130857212023-12-05 9:56:59130 days ago1701770219IN
0x91456757...8AFfDdbc2
0 ETH0.000005310.00951615
Execute Order1130845712023-12-05 9:18:39130 days ago1701767919IN
0x91456757...8AFfDdbc2
0 ETH0.000015660.01126523
Execute Order1130845552023-12-05 9:18:07130 days ago1701767887IN
0x91456757...8AFfDdbc2
0 ETH0.00001630.01170774
Execute Order1130845262023-12-05 9:17:09130 days ago1701767829IN
0x91456757...8AFfDdbc2
0 ETH0.000018980.01230538
Execute Order1130843952023-12-05 9:12:47130 days ago1701767567IN
0x91456757...8AFfDdbc2
0 ETH0.000005240.0096776
Execute Order1130815062023-12-05 7:36:29130 days ago1701761789IN
0x91456757...8AFfDdbc2
0 ETH0.000013020.0126588
Execute Order1130804582023-12-05 7:01:33130 days ago1701759693IN
0x91456757...8AFfDdbc2
0 ETH0.000017380.012247
Execute Order1130774252023-12-05 5:20:27130 days ago1701753627IN
0x91456757...8AFfDdbc2
0 ETH0.000020180.01707341
Execute Order1130760192023-12-05 4:33:35130 days ago1701750815IN
0x91456757...8AFfDdbc2
0 ETH0.000044360.09368948
Execute Order1130723652023-12-05 2:31:47130 days ago1701743507IN
0x91456757...8AFfDdbc2
0 ETH0.000127140.1178475
Execute Order1130720342023-12-05 2:20:45130 days ago1701742845IN
0x91456757...8AFfDdbc2
0 ETH0.000130430.09607736
Execute Order1130712052023-12-05 1:53:07130 days ago1701741187IN
0x91456757...8AFfDdbc2
0 ETH0.000194930.10602364
Execute Order1130711342023-12-05 1:50:45130 days ago1701741045IN
0x91456757...8AFfDdbc2
0 ETH0.000071740.11197274
Execute Order1130704012023-12-05 1:26:19130 days ago1701739579IN
0x91456757...8AFfDdbc2
0 ETH0.000006520.01287958
Execute Order1130703732023-12-05 1:25:23130 days ago1701739523IN
0x91456757...8AFfDdbc2
0.00542739 ETH0.00002360.01269986
Execute Order1130655582023-12-04 22:44:53130 days ago1701729893IN
0x91456757...8AFfDdbc2
0 ETH0.000223890.11811799
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Txn Hash Block From To Value
1131158342023-12-06 2:40:45129 days ago1701830445
0x91456757...8AFfDdbc2
0.45641905 ETH
1131158342023-12-06 2:40:45129 days ago1701830445
0x91456757...8AFfDdbc2
0.45641905 ETH
1130929992023-12-05 13:59:35130 days ago1701784775
0x91456757...8AFfDdbc2
0.0065 ETH
1130929992023-12-05 13:59:35130 days ago1701784775
0x91456757...8AFfDdbc2
0.0065 ETH
1130929672023-12-05 13:58:31130 days ago1701784711
0x91456757...8AFfDdbc2
0.005 ETH
1130929672023-12-05 13:58:31130 days ago1701784711
0x91456757...8AFfDdbc2
0.005 ETH
1130774252023-12-05 5:20:27130 days ago1701753627
0x91456757...8AFfDdbc2
0.20029708 ETH
1130774252023-12-05 5:20:27130 days ago1701753627
0x91456757...8AFfDdbc2
0.10027613 ETH
1130774252023-12-05 5:20:27130 days ago1701753627
0x91456757...8AFfDdbc2
0.10002095 ETH
1130703732023-12-05 1:25:23130 days ago1701739523
0x91456757...8AFfDdbc2
0.00271369 ETH
1130703732023-12-05 1:25:23130 days ago1701739523
0x91456757...8AFfDdbc2
0.00271369 ETH
1130516122023-12-04 15:00:01131 days ago1701702001
0x91456757...8AFfDdbc2
0.0115 ETH
1130516122023-12-04 15:00:01131 days ago1701702001
0x91456757...8AFfDdbc2
0.0115 ETH
1130515922023-12-04 14:59:21131 days ago1701701961
0x91456757...8AFfDdbc2
0.16 ETH
1130515662023-12-04 14:58:29131 days ago1701701909
0x91456757...8AFfDdbc2
0.1125 ETH
1130515662023-12-04 14:58:29131 days ago1701701909
0x91456757...8AFfDdbc2
0.1125 ETH
1130515012023-12-04 14:56:19131 days ago1701701779
0x91456757...8AFfDdbc2
0.40952507 ETH
1130515012023-12-04 14:56:19131 days ago1701701779
0x91456757...8AFfDdbc2
0.20406502 ETH
1130515012023-12-04 14:56:19131 days ago1701701779
0x91456757...8AFfDdbc2
0.20546004 ETH
1130510712023-12-04 14:41:59131 days ago1701700919
0x91456757...8AFfDdbc2
0.31 ETH
1130332602023-12-04 4:48:17131 days ago1701665297
0x91456757...8AFfDdbc2
0.0113 ETH
1130305222023-12-04 3:17:01131 days ago1701659821
0x91456757...8AFfDdbc2
0.0445 ETH
1130305222023-12-04 3:17:01131 days ago1701659821
0x91456757...8AFfDdbc2
0.0445 ETH
1130290762023-12-04 2:28:49131 days ago1701656929
0x91456757...8AFfDdbc2
0.10091079 ETH
1130290762023-12-04 2:28:49131 days ago1701656929
0x91456757...8AFfDdbc2
0.0836742 ETH
View All Internal Transactions

Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
BeefyZapRouter

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 1000000 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 14 : BeefyZapRouter.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.19;

import { SafeERC20, IERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { Pausable } from "@openzeppelin/contracts/security/Pausable.sol";
import { ReentrancyGuard } from "@openzeppelin/contracts/security/ReentrancyGuard.sol";

import { IBeefyTokenManager } from "../interfaces/IBeefyTokenManager.sol";
import { IBeefyZapRouter } from "../interfaces/IBeefyZapRouter.sol";
import { IPermit2 } from "../interfaces/IPermit2.sol";
import { BeefyTokenManager} from "./BeefyTokenManager.sol";
import { ZapErrors } from "./ZapErrors.sol";

/**
 * @title Zap router for Beefy vaults
 * @author kexley, Beefy
 * @notice Adaptable router for zapping tokens to and from Beefy vaults
 * @dev Router that allows arbitary calls to external contracts. Users can zap directly or sign 
 * using Permit2 to allow a relayer to execute zaps on their behalf. Do not directly approve this
 * contract for spending your tokens, approve the TokenManager instead
 */
contract BeefyZapRouter is IBeefyZapRouter, ZapErrors, Ownable, Pausable, ReentrancyGuard {
    using SafeERC20 for IERC20;

    /**
     * @dev Witness string used in signing an order
     */
    string private constant ORDER_STRING =
        "Order order)Order(Input[] inputs,Output[] outputs,Relay relay,address user,address recipient)Input(address token,uint256 amount)Output(address token,uint256 minOutputAmount)Relay(address target,uint256 value,bytes data)TokenPermissions(address token,uint256 amount)";
    /**
     * @dev Witness typehash used in signing an order
     */
    bytes32 private constant ORDER_TYPEHASH = 
        keccak256("Order(Input[] inputs,Output[] outputs,Relay relay,address user,address recipient)Input(address token,uint256 amount)Output(address token,uint256 minOutputAmount)Relay(address target,uint256 value,bytes data)");
    /**
     * @notice Permit2 immutable address
     */
    address public immutable permit2;
    /**
     * @notice Token manager immutable address
     */
    address public immutable tokenManager;

    /**
     * @notice Token and amount sent to the recipient at end of a zap
     * @param token Address of the token sent to recipient
     * @param amount Amount of the token sent to the recipient
     */
    event TokenReturned(address indexed token, uint256 amount);
    /**
     * @notice External relay call at end of zap
     * @param target Address of the target
     * @param value Ether value of the call
     * @param data Payload of the external call
     */
    event RelayData(address indexed target, uint256 value, bytes data);
    /**
     * @notice Completed order
     * @param order Order that has been fulfilled
     * @param caller Address of the order's executor
     * @param recipient Address of the order's recipient
     */
    event FulfilledOrder(Order indexed order, address indexed caller, address indexed recipient);

    /**
     * @dev Initialize permit2 address and create an implementation of the token manager
     * @param _permit2 Address for the permit2 contract
     */
    constructor(address _permit2) {
        permit2 = _permit2;
        tokenManager = address(new BeefyTokenManager());
    }

    /**
     * @notice Execute an order directly
     * @dev The user executes their own order directly. User must have already approved the token
     * manager to move the tokens
     * @param _order Order containing how many tokens to pull and the slippage amounts on outputs
     * @param _route Route containing the steps to reach the output
     */
    function executeOrder(Order calldata _order, Step[] calldata _route) external payable nonReentrant whenNotPaused {
        if (msg.sender != _order.user) revert InvalidCaller(_order.user, msg.sender);

        IBeefyTokenManager(tokenManager).pullTokens(_order.user, _order.inputs);
        _executeOrder(_order, _route);
    }

    /**
     * @notice Execute an order using a signature from the input token owner
     * @dev Execute an order indirectly by passing a signed permit from Permit2 that contains the
     * order as witness data. The user who owns the tokens must have already approved Permit2.
     * Route is supplied at this stage as slippages and amounts are already set in the signed order
     * @param _permit Struct of tokens that have been permitted and the nonce/deadline
     * @param _order Order that details the input/output tokens and amounts
     * @param _signature Resulting string from signing the permit and order data
     * @param _route Actual steps that will transform input tokens to output tokens
     */
    function executeOrder(
        IPermit2.PermitBatchTransferFrom calldata _permit,
        Order calldata _order,
        bytes calldata _signature,
        Step[] calldata _route
    ) external nonReentrant whenNotPaused {
        IPermit2(permit2).permitWitnessTransferFrom(
            _permit,
            _getTransferDetails(_order.inputs),
            _order.user,
            keccak256(abi.encode(ORDER_TYPEHASH, _order)),
            ORDER_STRING,
            _signature
        );

        _executeOrder(_order, _route);
    }

    /**
     * @dev Executes a valid order by executing the steps on the route, validating the output
     * amounts and then sending them to the recipient. A final external call is made to relay
     * data in the order to chain together calls
     * @param _order Order struct with details of inputs and outputs
     * @param _route Actual steps to transform inputs to outputs
     */
    function _executeOrder(Order calldata _order, Step[] calldata _route) private {
        _executeSteps(_route);
        _returnAssets(_order.outputs, _order.recipient, _order.relay.value);
        _executeRelay(_order.relay);

        emit FulfilledOrder(_order, msg.sender, _order.recipient);
    }

    /**
     * @dev Executes various steps to achieve the order outputs by making external calls. Balance
     * data is dynamically inserted into payloads to always move the full balances of this contract
     * @param _route Array of the steps the contract will execute
     */
    function _executeSteps(Step[] calldata _route) private {
        uint256 routeLength = _route.length;
        for (uint256 i; i < routeLength;) {
            Step calldata step = _route[i];
            (
                address stepTarget,
                uint256 value,
                bytes memory callData,
                bytes calldata stepData,
                StepToken[] calldata stepTokens
            ) = (step.target, step.value, step.data, step.data, step.tokens);

            if (stepTarget == permit2 || stepTarget == tokenManager) revert TargetingInvalidContract(stepTarget);

            uint256 balance;

            uint256 stepTokensLength = stepTokens.length;
            for (uint256 j; j < stepTokensLength;) {
                StepToken calldata stepToken = stepTokens[j];
                (address stepTokenAddress, int32 stepTokenIndex) = (stepToken.token, stepToken.index);

                if (stepTokenAddress == address(0)) {
                    value = address(this).balance;
                } else {
                    balance = IERC20(stepTokenAddress).balanceOf(address(this));
                    _approveToken(stepTokenAddress, stepTarget, balance);

                    if (stepTokenIndex >= 0) {
                        uint256 idx = uint256(int256(stepTokenIndex));
                        callData = bytes.concat(stepData[:idx], abi.encode(balance), stepData[idx + 32:]);
                    }
                }

                unchecked {
                    ++j;
                }
            }

            (bool success, bytes memory result) = stepTarget.call{value: value}(callData);
            if (!success) _propagateError(stepTarget, value, callData, result);

            unchecked {
                ++i;
            }
        }
    }

    /**
     * @dev Approve a token to be spent by an address if not already approved enough
     * @param _token Address of token to be approved
     * @param _spender Address of spender that will be allowed to move tokens
     * @param _amount Number of tokens that are going to be spent
     */
    function _approveToken(address _token, address _spender, uint256 _amount) private {
        if (IERC20(_token).allowance(address(this), _spender) < _amount) {
            IERC20(_token).forceApprove(_spender, type(uint256).max);
        }
    }

    /**
     * @dev Bubble up an error message from an underlying contract
     * @param _target Address that the call was sent to
     * @param _value Amount of ether sent with the call
     * @param _data Payload data of the call
     * @param _returnedData Returned data from the call
     */
    function _propagateError(address _target, uint256 _value, bytes memory _data, bytes memory _returnedData)
        private
        pure
    {
        if (_returnedData.length == 0) revert CallFailed(_target, _value, _data);
        assembly {
            revert(add(32, _returnedData), mload(_returnedData))
        }
    }

    /**
     * @dev Return the outputs to the recipient address
     * @param _outputs Token addresses and amounts to validate against to ensure no major slippage
     * @param _recipient Address of the receiver of the outputs
     * @param _relayValue Unwrapped native amount that is reserved for calling the relay address
     */
    function _returnAssets(Output[] calldata _outputs, address _recipient, uint256 _relayValue) private {
        uint256 balance;
        uint256 outputsLength = _outputs.length;
        for (uint256 i; i < outputsLength;) {
            Output calldata output = _outputs[i];
            (address outputToken, uint256 outputMinAmount) = (output.token, output.minOutputAmount);
            if (outputToken == address(0)) {
                balance = address(this).balance;
                if (balance < outputMinAmount) {
                    revert Slippage(outputToken, outputMinAmount, balance);
                }
                if (balance > _relayValue) {
                    balance -= _relayValue;
                    (bool success,) = _recipient.call{value: balance}("");
                    if (!success) revert EtherTransferFailed(_recipient);
                }
            } else {
                balance = IERC20(outputToken).balanceOf(address(this));
                if (balance < outputMinAmount) {
                    revert Slippage(outputToken, outputMinAmount, balance);
                } else if (balance > 0) {
                    IERC20(outputToken).safeTransfer(_recipient, balance);
                }
            }

            emit TokenReturned(outputToken, balance);

            unchecked {
                ++i;
            }
        }
    }

    /**
     * @dev Call an external contract at the end of a zap with a payload signed in the order
     * @param _relay Target address and payload data in a struct
     */
    function _executeRelay(Relay calldata _relay) private {
        (address relayTarget, uint256 relayValue, bytes calldata relaydata) 
            = (_relay.target, _relay.value, _relay.data);
        if (relayTarget != address(0)) {
            if (relayTarget == permit2 || relayTarget == tokenManager) {
                revert TargetingInvalidContract(relayTarget);
            }

            if (address(this).balance < relayValue) {
                revert InsufficientRelayValue(address(this).balance, relayValue);
            }

            (bool success, bytes memory result) = relayTarget.call{value: relayValue}(relaydata);
            if (!success) _propagateError(relayTarget, relayValue, relaydata, result);

            emit RelayData(relayTarget, relayValue, relaydata);
        }
    }

    /**
     * @dev Parse the token transfer details from the order so it can be supplied to the Permit2
     * transfer from request
     * @param _inputs Token addresses and amounts in a struct
     * @return transferDetails Transformed data
     */
    function _getTransferDetails(Input[] calldata _inputs)
        private
        view
        returns (IPermit2.SignatureTransferDetails[] memory)
    {
        uint256 inputsLength = _inputs.length;
        IPermit2.SignatureTransferDetails[] memory transferDetails =
            new IPermit2.SignatureTransferDetails[](inputsLength);
        
        for (uint256 i; i < inputsLength;) {
            transferDetails[i] =
                IPermit2.SignatureTransferDetails({to: address(this), requestedAmount: _inputs[i].amount});

            unchecked {
                ++i;
            }
        }
        return transferDetails;
    }

    /**
     * @notice Pause the contract from carrying out any more zaps
     * @dev Only owner can pause
     */
    function pause() external onlyOwner {
        _pause();
    }

    /**
     * @notice Unpause the contract to allow new zaps
     * @dev Only owner can unpause
     */
    function unpause() external onlyOwner {
        _unpause();
    }

    /**
     * @dev Allow receiving of native tokens
     */
    receive() external payable {}
}

File 2 of 14 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

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

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

File 3 of 14 : Pausable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)

pragma solidity ^0.8.0;

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

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract Pausable is Context {
    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    bool private _paused;

    /**
     * @dev Initializes the contract in unpaused state.
     */
    constructor() {
        _paused = false;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        _requireNotPaused();
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        _requirePaused();
        _;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        return _paused;
    }

    /**
     * @dev Throws if the contract is paused.
     */
    function _requireNotPaused() internal view virtual {
        require(!paused(), "Pausable: paused");
    }

    /**
     * @dev Throws if the contract is not paused.
     */
    function _requirePaused() internal view virtual {
        require(paused(), "Pausable: not paused");
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }
}

File 4 of 14 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be _NOT_ENTERED
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == _ENTERED;
    }
}

File 5 of 14 : 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 6 of 14 : 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 7 of 14 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (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. Compatible with tokens that require the approval to be set to
     * 0 before setting it to a non-zero value.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.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 8 of 14 : 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);
        }
    }
}

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

pragma solidity ^0.8.0;

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

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

File 10 of 14 : IBeefyTokenManager.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.19;

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

/**
 * @title Token manager interface
 * @author kexley, Beefy
 * @notice Interface for the token manager
 */
interface IBeefyTokenManager {
    /**
     * @notice Pull tokens from a user
     * @param _user Address of user to transfer tokens from
     * @param _inputs Addresses and amounts of tokens to transfer
     */
    function pullTokens(address _user, IBeefyZapRouter.Input[] calldata _inputs) external;
}

File 11 of 14 : IBeefyZapRouter.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.19;

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

/**
 * @title Zap router interface
 * @author kexley, Beefy
 * @notice Interface for zap router that contains the structs for orders and routes
 */
interface IBeefyZapRouter {
    /**
     * @dev Input token and amount used in a step of the zap
     * @param token Address of token
     * @param amount Amount of token
     */
    struct Input {
        address token;
        uint256 amount;
    }

    /**
     * @dev Output token and amount from the end of the zap
     * @param token Address of token
     * @param minOutputAmount Minimum amount of token received
     */
    struct Output {
        address token;
        uint256 minOutputAmount;
    }

    /**
     * @dev External call at the end of zap
     * @param target Target address to be called
     * @param value Ether value of the call
     * @param data Payload to call target address with
     */
    struct Relay {
        address target;
        uint256 value;
        bytes data;
    }

    /**
     * @dev Token relevant to the current step of the route
     * @param token Address of token
     * @param index Location in the data that the balance of the token should be inserted
     */
    struct StepToken {
        address token;
        int32 index;
    }

    /**
     * @dev Step in a route
     * @param target Target address to be called
     * @param value Ether value to call the target address with
     * @param data Payload to call target address with
     * @param tokens Tokens relevant to the step that require approvals or their balances inserted
     * into the data
     */
    struct Step {
        address target;
        uint256 value;
        bytes data;
        StepToken[] tokens;
    }

    /**
     * @dev Order created by the user
     * @param inputs Tokens and amounts to be pulled from the user
     * @param outputs Tokens and minimums to be sent to recipient
     * @param relay External call to make after zap is completed
     * @param user Source of input tokens
     * @param recipient Destination of output tokens
     */
    struct Order {
        Input[] inputs;
        Output[] outputs;
        Relay relay;
        address user;
        address recipient;
    }

    /**
     * @notice Execute an order directly
     * @param _order Order created by the user
     * @param _route Route supplied by user
     */
    function executeOrder(Order calldata _order, Step[] calldata _route) external payable;

    /**
     * @notice Execute an order on behalf of a user
     * @param _permit Token permits from Permit2 with the order as witness data signed by user
     * @param _order Order created by user that was signed in the permit
     * @param _signature Signature from user of combined permit and order
     * @param _route Route supplied by user or third-party
     */
    function executeOrder(
        IPermit2.PermitBatchTransferFrom calldata _permit,
        Order calldata _order,
        bytes calldata _signature,
        Step[] calldata _route
    ) external;

    /**
     * @notice Pause the contract from carrying out any more zaps
     * @dev Only owner can pause
     */
    function pause() external;

    /**
     * @notice Unpause the contract to allow new zaps
     * @dev Only owner can unpause
     */
    function unpause() external;

    /**
     * @notice Permit2 immutable address
     */
    function permit2() external view returns (address);

    /**
     * @notice Token manager immutable address
     */
    function tokenManager() external view returns (address);
}

File 12 of 14 : IPermit2.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.19;

/**
 * @title Permit2 interface
 * @author kexley, Beefy
 * @notice Interface for Permit2
 */
interface IPermit2 {
    /**
     * @dev Token and amount in a permit message
     * @param token Address of token to transfer
     * @param amount Amount of token to transfer
     */
    struct TokenPermissions {
        address token;
        uint256 amount;
    }

    /**
     * @dev Batched permit with the unique nonce and deadline
     * @param permitted Tokens and corresponding amounts permitted for a transfer
     * @param nonce Unique value for every token owner's signature to prevent signature replays
     * @param deadline Deadline on the permit signature
     */
    struct PermitBatchTransferFrom {
        TokenPermissions[] permitted;
        uint256 nonce;
        uint256 deadline;
    }

    /**
     * @dev Transfer details for permitBatchTransferFrom
     * @param to Recipient of tokens
     * @param requestedAmount Amount to transfer
     */
    struct SignatureTransferDetails {
        address to;
        uint256 requestedAmount;
    }

    /**
     * @notice Consume a permit2 message and transfer tokens
     * @param permit Batched permit
     * @param transferDetails Recipient and amount of tokens to transfer
     * @param owner Source of tokens
     * @param witness Verified order data that was witnessed in the permit2 signature
     * @param witnessTypeString Order function string used to create EIP-712 type string
     * @param signature Signature from user
     */
    function permitWitnessTransferFrom(
        PermitBatchTransferFrom memory permit,
        SignatureTransferDetails[] calldata transferDetails,
        address owner,
        bytes32 witness,
        string calldata witnessTypeString,
        bytes calldata signature
    ) external;

    /**
     * @notice Domain separator to differentiate the chain a permit exists on
     */
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

File 13 of 14 : BeefyTokenManager.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.19;

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

/**
 * @title Token manager
 * @author kexley, Beefy
 * @notice Token manager handles the token approvals for the zap router
 * @dev Users should approve this contract instead of the zap router to handle the input ERC20 tokens
 */
contract BeefyTokenManager is ZapErrors {
    using SafeERC20 for IERC20;

    /**
     * @notice Zap router immutable address
     */
    address public immutable zap;

    /**
     * @dev This contract is created in the constructor of the zap router
     */
    constructor() {
        zap = msg.sender;
    }

    /**
     * @notice Pulls tokens from a user and transfers them directly to the zap router
     * @dev Only the token owner can call this function indirectly via the zap router
     * @param _user Address to pull tokens from
     * @param _inputs Token addresses and amounts to pull
     */
    function pullTokens(address _user, IBeefyZapRouter.Input[] calldata _inputs) external {
        if (msg.sender != zap) revert CallerNotZap(msg.sender);
        uint256 inputLength = _inputs.length;
        for (uint256 i; i < inputLength;) {
            IBeefyZapRouter.Input calldata input = _inputs[i];
            unchecked {
                ++i;
            }

            if (input.token == address(0)) continue;
            IERC20(input.token).safeTransferFrom(_user, msg.sender, input.amount);
        }
    }
}

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

pragma solidity 0.8.19;

/**
 * @title Zap errors
 * @author kexley, Beefy
 * @notice Custom errors for the zap router
 */
contract ZapErrors {
    error InvalidCaller(address owner, address caller);
    error TargetingInvalidContract(address target);
    error CallFailed(address target, uint256 value, bytes callData);
    error Slippage(address token, uint256 minAmountOut, uint256 balance);
    error EtherTransferFailed(address recipient);
    error CallerNotZap(address caller);
    error InsufficientRelayValue(uint256 balance, uint256 relayValue);
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_permit2","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"callData","type":"bytes"}],"name":"CallFailed","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"CallerNotZap","type":"error"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"}],"name":"EtherTransferFailed","type":"error"},{"inputs":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"relayValue","type":"uint256"}],"name":"InsufficientRelayValue","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"caller","type":"address"}],"name":"InvalidCaller","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"uint256","name":"balance","type":"uint256"}],"name":"Slippage","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"TargetingInvalidContract","type":"error"},{"anonymous":false,"inputs":[{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct IBeefyZapRouter.Input[]","name":"inputs","type":"tuple[]"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"minOutputAmount","type":"uint256"}],"internalType":"struct IBeefyZapRouter.Output[]","name":"outputs","type":"tuple[]"},{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct IBeefyZapRouter.Relay","name":"relay","type":"tuple"},{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"indexed":true,"internalType":"struct IBeefyZapRouter.Order","name":"order","type":"tuple"},{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"}],"name":"FulfilledOrder","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"RelayData","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokenReturned","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct IPermit2.TokenPermissions[]","name":"permitted","type":"tuple[]"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IPermit2.PermitBatchTransferFrom","name":"_permit","type":"tuple"},{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct IBeefyZapRouter.Input[]","name":"inputs","type":"tuple[]"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"minOutputAmount","type":"uint256"}],"internalType":"struct IBeefyZapRouter.Output[]","name":"outputs","type":"tuple[]"},{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct IBeefyZapRouter.Relay","name":"relay","type":"tuple"},{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"internalType":"struct IBeefyZapRouter.Order","name":"_order","type":"tuple"},{"internalType":"bytes","name":"_signature","type":"bytes"},{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"int32","name":"index","type":"int32"}],"internalType":"struct IBeefyZapRouter.StepToken[]","name":"tokens","type":"tuple[]"}],"internalType":"struct IBeefyZapRouter.Step[]","name":"_route","type":"tuple[]"}],"name":"executeOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct IBeefyZapRouter.Input[]","name":"inputs","type":"tuple[]"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"minOutputAmount","type":"uint256"}],"internalType":"struct IBeefyZapRouter.Output[]","name":"outputs","type":"tuple[]"},{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct IBeefyZapRouter.Relay","name":"relay","type":"tuple"},{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"internalType":"struct IBeefyZapRouter.Order","name":"_order","type":"tuple"},{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"int32","name":"index","type":"int32"}],"internalType":"struct IBeefyZapRouter.StepToken[]","name":"tokens","type":"tuple[]"}],"internalType":"struct IBeefyZapRouter.Step[]","name":"_route","type":"tuple[]"}],"name":"executeOrder","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"permit2","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"tokenManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60c06040523480156200001157600080fd5b5060405162003158380380620031588339810160408190526200003491620000fa565b6200003f336200009c565b6000805460ff60a01b19169055600180556001600160a01b0381166080526040516200006b90620000ec565b604051809103906000f08015801562000088573d6000803e3d6000fd5b506001600160a01b031660a052506200012c565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b61079380620029c583390190565b6000602082840312156200010d57600080fd5b81516001600160a01b03811681146200012557600080fd5b9392505050565b60805160a05161284a6200017b600039600081816101310152818161054d01528181610b8a015261122501526000818160d30152818161027401528181610b4501526111d0015261284a6000f3fe6080604052600436106100b55760003560e01c8063715018a6116100695780638da5cb5b1161004e5780638da5cb5b146101ef578063f2fde38b1461021a578063f41b2db61461023a57600080fd5b8063715018a6146101c55780638456cb59146101da57600080fd5b80632e0af5e51161009a5780632e0af5e5146101535780633f4ba83a146101755780635c975abb1461018a57600080fd5b806312261ee7146100c15780632a709b141461011f57600080fd5b366100bc57005b600080fd5b3480156100cd57600080fd5b506100f57f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561012b57600080fd5b506100f57f000000000000000000000000000000000000000000000000000000000000000081565b34801561015f57600080fd5b5061017361016e366004611bcb565b61024d565b005b34801561018157600080fd5b50610173610393565b34801561019657600080fd5b5060005474010000000000000000000000000000000000000000900460ff166040519015158152602001610116565b3480156101d157600080fd5b506101736103a5565b3480156101e657600080fd5b506101736103b7565b3480156101fb57600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff166100f5565b34801561022657600080fd5b50610173610235366004611ce3565b6103c7565b610173610248366004611d05565b610483565b6102556105f5565b61025d610668565b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001663fe8ec1a7876102ac6102a78980611d6e565b6106ed565b6102bc60808a0160608b01611ce3565b7fc709880ce3db9deadf408dae85548b37e4530edc88a93e955bd080b45f3255c28a6040516020016102ef929190611fe0565b60405160208183030381529060405280519060200120604051806101400160405280610109815260200161270c61010991398a8a6040518863ffffffff1660e01b815260040161034597969594939291906121c8565b600060405180830381600087803b15801561035f57600080fd5b505af1158015610373573d6000803e3d6000fd5b505050506103828583836107d4565b61038b60018055565b505050505050565b61039b6108a9565b6103a361092a565b565b6103ad6108a9565b6103a360006109a7565b6103bf6108a9565b6103a3610a1c565b6103cf6108a9565b73ffffffffffffffffffffffffffffffffffffffff8116610477576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b610480816109a7565b50565b61048b6105f5565b610493610668565b6104a36080840160608501611ce3565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610536576104e56080840160608501611ce3565b6040517f16cece4800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff909116600482015233602482015260440161046e565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166377fc3fa86105826080860160608701611ce3565b61058c8680611d6e565b6040518463ffffffff1660e01b81526004016105aa939291906122a0565b600060405180830381600087803b1580156105c457600080fd5b505af11580156105d8573d6000803e3d6000fd5b505050506105e78383836107d4565b6105f060018055565b505050565b600260015403610661576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161046e565b6002600155565b60005474010000000000000000000000000000000000000000900460ff16156103a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015260640161046e565b60608160008167ffffffffffffffff81111561070b5761070b612300565b60405190808252806020026020018201604052801561075057816020015b60408051808201909152600080825260208201528152602001906001900390816107295790505b50905060005b828110156107c95760405180604001604052803073ffffffffffffffffffffffffffffffffffffffff1681526020018787848181106107975761079761232f565b905060400201602001358152508282815181106107b6576107b661232f565b6020908102919091010152600101610756565b509150505b92915050565b6107de8282610a8b565b6108146107ee6020850185611d6e565b6107fe60a0870160808801611ce3565b61080b604088018861235e565b60200135610e78565b610829610824604085018561235e565b611184565b61083960a0840160808501611ce3565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1684604051610874919061241b565b604051908190038120907f1ba5b6ed656994657175705961138c96bd8ec133c35817fa85903f450129e0b190600090a4505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146103a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161046e565b61093261141b565b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b610a24610668565b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861097d3390565b8060005b81811015610e725736848483818110610aaa57610aaa61232f565b9050602002810190610abc91906124dd565b90506000808036818181610ad36020890189611ce3565b6020890135610ae560408b018b612511565b610af260408d018d612511565b610aff60608f018f611d6e565b97509750975097508080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250949b5092995090975050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff90811690891614905080610bd857507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff16145b15610c27576040517f781568a400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8816600482015260240161046e565b600081815b81811015610dd95736858583818110610c4757610c4761232f565b6040029190910191506000905080610c626020840184611ce3565b610c726040850160208601612576565b909250905073ffffffffffffffffffffffffffffffffffffffff8216610c9a57479b50610dcb565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8316906370a0823190602401602060405180830381865afa158015610d04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d289190612599565b9550610d35828e8861149f565b60008160030b12610dcb57600381900b610d528160008c8e6125b2565b60408051602081018b905201604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190528d8d610d9986602061260b565b610da49282906125b2565b604051602001610db895949392919061261e565b6040516020818303038152906040529b50505b836001019350505050610c2c565b506000808a73ffffffffffffffffffffffffffffffffffffffff168a8a604051610e039190612652565b60006040518083038185875af1925050503d8060008114610e40576040519150601f19603f3d011682016040523d82523d6000602084013e610e45565b606091505b509150915081610e5b57610e5b8b8b8b8461157f565b8c6001019c50505050505050505050505050610a8f565b50505050565b600083815b8181101561117b5736878783818110610e9857610e9861232f565b6040029190910191506000905080610eb36020840184611ce3565b915050602082013573ffffffffffffffffffffffffffffffffffffffff82166110065747955080861015610f39576040517fd4cf45a200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83166004820152602481018290526044810187905260640161046e565b8686111561100157610f4b8787612664565b955060008873ffffffffffffffffffffffffffffffffffffffff168760405160006040518083038185875af1925050503d8060008114610fa7576040519150601f19603f3d011682016040523d82523d6000602084013e610fac565b606091505b5050905080610fff576040517f464e254d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a16600482015260240161046e565b505b61111d565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8316906370a0823190602401602060405180830381865afa158015611070573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110949190612599565b9550808610156110f6576040517fd4cf45a200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83166004820152602481018290526044810187905260640161046e565b851561111d5761111d73ffffffffffffffffffffffffffffffffffffffff831689886115c8565b8173ffffffffffffffffffffffffffffffffffffffff167feaf449319c042c9ba3474fa0c5329eb58cd1f23be110cdbf9d697b8d303dac158760405161116591815260200190565b60405180910390a2836001019350505050610e7d565b50505050505050565b60008036816111966020860186611ce3565b60208601356111a86040880188612511565b9296509094509250905073ffffffffffffffffffffffffffffffffffffffff841615611414577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16148061127357507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16145b156112c2576040517f781568a400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015260240161046e565b82471015611305576040517f74c8cbe60000000000000000000000000000000000000000000000000000000081524760048201526024810184905260440161046e565b6000808573ffffffffffffffffffffffffffffffffffffffff16858585604051611330929190612677565b60006040518083038185875af1925050503d806000811461136d576040519150601f19603f3d011682016040523d82523d6000602084013e611372565b606091505b5091509150816113bf576113bf868686868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525087925061157f915050565b8573ffffffffffffffffffffffffffffffffffffffff167f6c936258f37a22c831493e49cb45429bdf7b6bb0e261f271a15f084e5b08aaff86868660405161140993929190612687565b60405180910390a250505b5050505050565b60005474010000000000000000000000000000000000000000900460ff166103a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f7420706175736564000000000000000000000000604482015260640161046e565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff838116602483015282919085169063dd62ed3e90604401602060405180830381865afa158015611514573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115389190612599565b10156105f0576105f073ffffffffffffffffffffffffffffffffffffffff8416837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61169c565b80516000036115c0578383836040517fe1eec8f100000000000000000000000000000000000000000000000000000000815260040161046e939291906126a1565b805181602001fd5b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526105f09084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152611788565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b3000000000000000000000000000000000000000000000000000000001790526117288482611897565b610e725760405173ffffffffffffffffffffffffffffffffffffffff84166024820152600060448201526117829085907f095ea7b3000000000000000000000000000000000000000000000000000000009060640161161a565b610e7284825b60006117ea826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166119589092919063ffffffff16565b905080516000148061180b57508080602001905181019061180b91906126d6565b6105f0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840161046e565b60008060008473ffffffffffffffffffffffffffffffffffffffff16846040516118c19190612652565b6000604051808303816000865af19150503d80600081146118fe576040519150601f19603f3d011682016040523d82523d6000602084013e611903565b606091505b509150915081801561192d57508051158061192d57508080602001905181019061192d91906126d6565b801561194f575073ffffffffffffffffffffffffffffffffffffffff85163b15155b95945050505050565b6060611967848460008561196f565b949350505050565b606082471015611a01576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c0000000000000000000000000000000000000000000000000000606482015260840161046e565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051611a2a9190612652565b60006040518083038185875af1925050503d8060008114611a67576040519150601f19603f3d011682016040523d82523d6000602084013e611a6c565b606091505b5091509150611a7d87838387611a88565b979650505050505050565b60608315611b1e578251600003611b175773ffffffffffffffffffffffffffffffffffffffff85163b611b17576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161046e565b5081611967565b6119678383815115611b335781518083602001fd5b806040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161046e91906126f8565b600060a08284031215611b7957600080fd5b50919050565b60008083601f840112611b9157600080fd5b50813567ffffffffffffffff811115611ba957600080fd5b6020830191508360208260051b8501011115611bc457600080fd5b9250929050565b60008060008060008060808789031215611be457600080fd5b863567ffffffffffffffff80821115611bfc57600080fd5b908801906060828b031215611c1057600080fd5b90965060208801359080821115611c2657600080fd5b611c328a838b01611b67565b96506040890135915080821115611c4857600080fd5b818901915089601f830112611c5c57600080fd5b813581811115611c6b57600080fd5b8a6020828501011115611c7d57600080fd5b602083019650809550506060890135915080821115611c9b57600080fd5b50611ca889828a01611b7f565b979a9699509497509295939492505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611cde57600080fd5b919050565b600060208284031215611cf557600080fd5b611cfe82611cba565b9392505050565b600080600060408486031215611d1a57600080fd5b833567ffffffffffffffff80821115611d3257600080fd5b611d3e87838801611b67565b94506020860135915080821115611d5457600080fd5b50611d6186828701611b7f565b9497909650939450505050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112611da357600080fd5b83018035915067ffffffffffffffff821115611dbe57600080fd5b6020019150600681901b3603821315611bc457600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112611e0b57600080fd5b830160208101925035905067ffffffffffffffff811115611e2b57600080fd5b8060061b3603821315611bc457600080fd5b73ffffffffffffffffffffffffffffffffffffffff611e5b82611cba565b168252602090810135910152565b81835260208301925060008160005b84811015611e9d57611e8a8683611e3d565b6040958601959190910190600101611e78565b5093949350505050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa1833603018112611edb57600080fd5b90910192915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112611f1957600080fd5b830160208101925035905067ffffffffffffffff811115611f3957600080fd5b803603821315611bc457600080fd5b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b73ffffffffffffffffffffffffffffffffffffffff611faf82611cba565b168252602081013560208301526000611fcb6040830183611ee4565b6060604086015261194f606086018284611f48565b6000604084835280602084015260e08301611ffb8586611dd6565b60a086850152918290529060009061010086015b81831015612033576120218185611e3d565b9284019260019290920191840161200f565b6120406020890189611dd6565b945092507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc091508187820301606088015261207c818585611e69565b93505061208b84880188611ea7565b93508086840301608087015250506120a38183611f91565b9150506120b260608501611cba565b73ffffffffffffffffffffffffffffffffffffffff1660a08401526120d960808501611cba565b73ffffffffffffffffffffffffffffffffffffffff811660c085015250949350505050565b600081518084526020808501945080840160005b8381101561214f578151805173ffffffffffffffffffffffffffffffffffffffff1688528301518388015260409096019590820190600101612112565b509495945050505050565b60005b8381101561217557818101518382015260200161215d565b50506000910152565b6000815180845261219681602086016020860161215a565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60c08152600061012082016121dd8a8b611dd6565b606060c0860152918290529060009061014085015b81831015612217576122048185611e3d565b60409384019360019390930192016121f2565b60208d013560e087015260408d0135610100870152858103602087015261223e818d6120fe565b9350505050612265604084018973ffffffffffffffffffffffffffffffffffffffff169052565b866060840152828103608084015261227d818761217e565b905082810360a0840152612292818587611f48565b9a9950505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff841681526040602082018190528181018390526000908460608401835b868110156122f4576122e48284611e3d565b91830191908301906001016122d2565b50979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa183360301811261239257600080fd5b9190910192915050565b73ffffffffffffffffffffffffffffffffffffffff6123ba82611cba565b1682526020810135602083015260006123d66040830183611ee4565b8082604087013760006040828701015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168601019250505092915050565b60006124278384611dd6565b8360005b828110156124505761243d8285611e3d565b604093840193919091019060010161242b565b5061245e6020870187611dd6565b935091506000905b8382101561248b576124788184611e3d565b6040928301926001929092019101612466565b611a7d6124d16124a7836124a260408c018c611ea7565b61239c565b6124b360608b01611cba565b73ffffffffffffffffffffffffffffffffffffffff16815260200190565b6124b360808a01611cba565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8183360301811261239257600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261254657600080fd5b83018035915067ffffffffffffffff82111561256157600080fd5b602001915036819003821315611bc457600080fd5b60006020828403121561258857600080fd5b81358060030b8114611cfe57600080fd5b6000602082840312156125ab57600080fd5b5051919050565b600080858511156125c257600080fd5b838611156125cf57600080fd5b5050820193919092039150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808201808211156107ce576107ce6125dc565b84868237600085820160008152855161263b818360208a0161215a565b018385823760009301928352509095945050505050565b6000825161239281846020870161215a565b818103818111156107ce576107ce6125dc565b8183823760009101908152919050565b83815260406020820152600061194f604083018486611f48565b73ffffffffffffffffffffffffffffffffffffffff8416815282602082015260606040820152600061194f606083018461217e565b6000602082840312156126e857600080fd5b81518015158114611cfe57600080fd5b602081526000611cfe602083018461217e56fe4f72646572206f72646572294f7264657228496e7075745b5d20696e707574732c4f75747075745b5d206f7574707574732c52656c61792072656c61792c6164647265737320757365722c6164647265737320726563697069656e7429496e707574286164647265737320746f6b656e2c75696e7432353620616d6f756e74294f7574707574286164647265737320746f6b656e2c75696e74323536206d696e4f7574707574416d6f756e742952656c61792861646472657373207461726765742c75696e743235362076616c75652c6279746573206461746129546f6b656e5065726d697373696f6e73286164647265737320746f6b656e2c75696e7432353620616d6f756e7429a2646970667358221220512457ca52bfc529d3aa7b321c2cb9ea86fcc2ba388bc6391744516f029360d164736f6c6343000813003360a060405234801561001057600080fd5b503360805260805161075e610035600039600081816040015260b8015261075e6000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063262d61521461003b57806377fc3fa81461008b575b600080fd5b6100627f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b61009e61009936600461059e565b6100a0565b005b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610116576040517f403e63e90000000000000000000000000000000000000000000000000000000081523360048201526024015b60405180910390fd5b8060005b818110156101b0573684848381811061013557610135610624565b600190940193604002919091019150600090506101556020830183610653565b73ffffffffffffffffffffffffffffffffffffffff1603610176575061011a565b6101aa86336020840180359061018c9086610653565b73ffffffffffffffffffffffffffffffffffffffff169291906101b7565b5061011a565b5050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd0000000000000000000000000000000000000000000000000000000017905261024c908590610252565b50505050565b60006102b4826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166103669092919063ffffffff16565b90508051600014806102d55750808060200190518101906102d59190610675565b610361576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840161010d565b505050565b6060610375848460008561037d565b949350505050565b60608247101561040f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c0000000000000000000000000000000000000000000000000000606482015260840161010d565b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161043891906106bb565b60006040518083038185875af1925050503d8060008114610475576040519150601f19603f3d011682016040523d82523d6000602084013e61047a565b606091505b509150915061048b87838387610496565b979650505050505050565b6060831561052c5782516000036105255773ffffffffffffffffffffffffffffffffffffffff85163b610525576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161010d565b5081610375565b61037583838151156105415781518083602001fd5b806040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161010d91906106d7565b803573ffffffffffffffffffffffffffffffffffffffff8116811461059957600080fd5b919050565b6000806000604084860312156105b357600080fd5b6105bc84610575565b9250602084013567ffffffffffffffff808211156105d957600080fd5b818601915086601f8301126105ed57600080fd5b8135818111156105fc57600080fd5b8760208260061b850101111561061157600080fd5b6020830194508093505050509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561066557600080fd5b61066e82610575565b9392505050565b60006020828403121561068757600080fd5b8151801515811461066e57600080fd5b60005b838110156106b257818101518382015260200161069a565b50506000910152565b600082516106cd818460208701610697565b9190910192915050565b60208152600082518060208401526106f6816040850160208701610697565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea2646970667358221220299c92bc4ed46081b3cb3ce14d83bcb0fa7406938e0e0f750575b6ea4b4c0cf364736f6c63430008130033000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3

Deployed Bytecode

0x6080604052600436106100b55760003560e01c8063715018a6116100695780638da5cb5b1161004e5780638da5cb5b146101ef578063f2fde38b1461021a578063f41b2db61461023a57600080fd5b8063715018a6146101c55780638456cb59146101da57600080fd5b80632e0af5e51161009a5780632e0af5e5146101535780633f4ba83a146101755780635c975abb1461018a57600080fd5b806312261ee7146100c15780632a709b141461011f57600080fd5b366100bc57005b600080fd5b3480156100cd57600080fd5b506100f57f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba381565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561012b57600080fd5b506100f57f000000000000000000000000afa91974e148c3cc4a39df42ccaa4c378a5be8e081565b34801561015f57600080fd5b5061017361016e366004611bcb565b61024d565b005b34801561018157600080fd5b50610173610393565b34801561019657600080fd5b5060005474010000000000000000000000000000000000000000900460ff166040519015158152602001610116565b3480156101d157600080fd5b506101736103a5565b3480156101e657600080fd5b506101736103b7565b3480156101fb57600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff166100f5565b34801561022657600080fd5b50610173610235366004611ce3565b6103c7565b610173610248366004611d05565b610483565b6102556105f5565b61025d610668565b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba31663fe8ec1a7876102ac6102a78980611d6e565b6106ed565b6102bc60808a0160608b01611ce3565b7fc709880ce3db9deadf408dae85548b37e4530edc88a93e955bd080b45f3255c28a6040516020016102ef929190611fe0565b60405160208183030381529060405280519060200120604051806101400160405280610109815260200161270c61010991398a8a6040518863ffffffff1660e01b815260040161034597969594939291906121c8565b600060405180830381600087803b15801561035f57600080fd5b505af1158015610373573d6000803e3d6000fd5b505050506103828583836107d4565b61038b60018055565b505050505050565b61039b6108a9565b6103a361092a565b565b6103ad6108a9565b6103a360006109a7565b6103bf6108a9565b6103a3610a1c565b6103cf6108a9565b73ffffffffffffffffffffffffffffffffffffffff8116610477576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b610480816109a7565b50565b61048b6105f5565b610493610668565b6104a36080840160608501611ce3565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610536576104e56080840160608501611ce3565b6040517f16cece4800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff909116600482015233602482015260440161046e565b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000afa91974e148c3cc4a39df42ccaa4c378a5be8e0166377fc3fa86105826080860160608701611ce3565b61058c8680611d6e565b6040518463ffffffff1660e01b81526004016105aa939291906122a0565b600060405180830381600087803b1580156105c457600080fd5b505af11580156105d8573d6000803e3d6000fd5b505050506105e78383836107d4565b6105f060018055565b505050565b600260015403610661576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161046e565b6002600155565b60005474010000000000000000000000000000000000000000900460ff16156103a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015260640161046e565b60608160008167ffffffffffffffff81111561070b5761070b612300565b60405190808252806020026020018201604052801561075057816020015b60408051808201909152600080825260208201528152602001906001900390816107295790505b50905060005b828110156107c95760405180604001604052803073ffffffffffffffffffffffffffffffffffffffff1681526020018787848181106107975761079761232f565b905060400201602001358152508282815181106107b6576107b661232f565b6020908102919091010152600101610756565b509150505b92915050565b6107de8282610a8b565b6108146107ee6020850185611d6e565b6107fe60a0870160808801611ce3565b61080b604088018861235e565b60200135610e78565b610829610824604085018561235e565b611184565b61083960a0840160808501611ce3565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1684604051610874919061241b565b604051908190038120907f1ba5b6ed656994657175705961138c96bd8ec133c35817fa85903f450129e0b190600090a4505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146103a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161046e565b61093261141b565b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b610a24610668565b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861097d3390565b8060005b81811015610e725736848483818110610aaa57610aaa61232f565b9050602002810190610abc91906124dd565b90506000808036818181610ad36020890189611ce3565b6020890135610ae560408b018b612511565b610af260408d018d612511565b610aff60608f018f611d6e565b97509750975097508080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250949b5092995090975050507f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba373ffffffffffffffffffffffffffffffffffffffff90811690891614905080610bd857507f000000000000000000000000afa91974e148c3cc4a39df42ccaa4c378a5be8e073ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff16145b15610c27576040517f781568a400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8816600482015260240161046e565b600081815b81811015610dd95736858583818110610c4757610c4761232f565b6040029190910191506000905080610c626020840184611ce3565b610c726040850160208601612576565b909250905073ffffffffffffffffffffffffffffffffffffffff8216610c9a57479b50610dcb565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8316906370a0823190602401602060405180830381865afa158015610d04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d289190612599565b9550610d35828e8861149f565b60008160030b12610dcb57600381900b610d528160008c8e6125b2565b60408051602081018b905201604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190528d8d610d9986602061260b565b610da49282906125b2565b604051602001610db895949392919061261e565b6040516020818303038152906040529b50505b836001019350505050610c2c565b506000808a73ffffffffffffffffffffffffffffffffffffffff168a8a604051610e039190612652565b60006040518083038185875af1925050503d8060008114610e40576040519150601f19603f3d011682016040523d82523d6000602084013e610e45565b606091505b509150915081610e5b57610e5b8b8b8b8461157f565b8c6001019c50505050505050505050505050610a8f565b50505050565b600083815b8181101561117b5736878783818110610e9857610e9861232f565b6040029190910191506000905080610eb36020840184611ce3565b915050602082013573ffffffffffffffffffffffffffffffffffffffff82166110065747955080861015610f39576040517fd4cf45a200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83166004820152602481018290526044810187905260640161046e565b8686111561100157610f4b8787612664565b955060008873ffffffffffffffffffffffffffffffffffffffff168760405160006040518083038185875af1925050503d8060008114610fa7576040519150601f19603f3d011682016040523d82523d6000602084013e610fac565b606091505b5050905080610fff576040517f464e254d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a16600482015260240161046e565b505b61111d565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8316906370a0823190602401602060405180830381865afa158015611070573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110949190612599565b9550808610156110f6576040517fd4cf45a200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83166004820152602481018290526044810187905260640161046e565b851561111d5761111d73ffffffffffffffffffffffffffffffffffffffff831689886115c8565b8173ffffffffffffffffffffffffffffffffffffffff167feaf449319c042c9ba3474fa0c5329eb58cd1f23be110cdbf9d697b8d303dac158760405161116591815260200190565b60405180910390a2836001019350505050610e7d565b50505050505050565b60008036816111966020860186611ce3565b60208601356111a86040880188612511565b9296509094509250905073ffffffffffffffffffffffffffffffffffffffff841615611414577f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba373ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16148061127357507f000000000000000000000000afa91974e148c3cc4a39df42ccaa4c378a5be8e073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16145b156112c2576040517f781568a400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015260240161046e565b82471015611305576040517f74c8cbe60000000000000000000000000000000000000000000000000000000081524760048201526024810184905260440161046e565b6000808573ffffffffffffffffffffffffffffffffffffffff16858585604051611330929190612677565b60006040518083038185875af1925050503d806000811461136d576040519150601f19603f3d011682016040523d82523d6000602084013e611372565b606091505b5091509150816113bf576113bf868686868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525087925061157f915050565b8573ffffffffffffffffffffffffffffffffffffffff167f6c936258f37a22c831493e49cb45429bdf7b6bb0e261f271a15f084e5b08aaff86868660405161140993929190612687565b60405180910390a250505b5050505050565b60005474010000000000000000000000000000000000000000900460ff166103a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f7420706175736564000000000000000000000000604482015260640161046e565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff838116602483015282919085169063dd62ed3e90604401602060405180830381865afa158015611514573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115389190612599565b10156105f0576105f073ffffffffffffffffffffffffffffffffffffffff8416837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61169c565b80516000036115c0578383836040517fe1eec8f100000000000000000000000000000000000000000000000000000000815260040161046e939291906126a1565b805181602001fd5b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526105f09084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152611788565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b3000000000000000000000000000000000000000000000000000000001790526117288482611897565b610e725760405173ffffffffffffffffffffffffffffffffffffffff84166024820152600060448201526117829085907f095ea7b3000000000000000000000000000000000000000000000000000000009060640161161a565b610e7284825b60006117ea826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166119589092919063ffffffff16565b905080516000148061180b57508080602001905181019061180b91906126d6565b6105f0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840161046e565b60008060008473ffffffffffffffffffffffffffffffffffffffff16846040516118c19190612652565b6000604051808303816000865af19150503d80600081146118fe576040519150601f19603f3d011682016040523d82523d6000602084013e611903565b606091505b509150915081801561192d57508051158061192d57508080602001905181019061192d91906126d6565b801561194f575073ffffffffffffffffffffffffffffffffffffffff85163b15155b95945050505050565b6060611967848460008561196f565b949350505050565b606082471015611a01576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c0000000000000000000000000000000000000000000000000000606482015260840161046e565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051611a2a9190612652565b60006040518083038185875af1925050503d8060008114611a67576040519150601f19603f3d011682016040523d82523d6000602084013e611a6c565b606091505b5091509150611a7d87838387611a88565b979650505050505050565b60608315611b1e578251600003611b175773ffffffffffffffffffffffffffffffffffffffff85163b611b17576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161046e565b5081611967565b6119678383815115611b335781518083602001fd5b806040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161046e91906126f8565b600060a08284031215611b7957600080fd5b50919050565b60008083601f840112611b9157600080fd5b50813567ffffffffffffffff811115611ba957600080fd5b6020830191508360208260051b8501011115611bc457600080fd5b9250929050565b60008060008060008060808789031215611be457600080fd5b863567ffffffffffffffff80821115611bfc57600080fd5b908801906060828b031215611c1057600080fd5b90965060208801359080821115611c2657600080fd5b611c328a838b01611b67565b96506040890135915080821115611c4857600080fd5b818901915089601f830112611c5c57600080fd5b813581811115611c6b57600080fd5b8a6020828501011115611c7d57600080fd5b602083019650809550506060890135915080821115611c9b57600080fd5b50611ca889828a01611b7f565b979a9699509497509295939492505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611cde57600080fd5b919050565b600060208284031215611cf557600080fd5b611cfe82611cba565b9392505050565b600080600060408486031215611d1a57600080fd5b833567ffffffffffffffff80821115611d3257600080fd5b611d3e87838801611b67565b94506020860135915080821115611d5457600080fd5b50611d6186828701611b7f565b9497909650939450505050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112611da357600080fd5b83018035915067ffffffffffffffff821115611dbe57600080fd5b6020019150600681901b3603821315611bc457600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112611e0b57600080fd5b830160208101925035905067ffffffffffffffff811115611e2b57600080fd5b8060061b3603821315611bc457600080fd5b73ffffffffffffffffffffffffffffffffffffffff611e5b82611cba565b168252602090810135910152565b81835260208301925060008160005b84811015611e9d57611e8a8683611e3d565b6040958601959190910190600101611e78565b5093949350505050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa1833603018112611edb57600080fd5b90910192915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112611f1957600080fd5b830160208101925035905067ffffffffffffffff811115611f3957600080fd5b803603821315611bc457600080fd5b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b73ffffffffffffffffffffffffffffffffffffffff611faf82611cba565b168252602081013560208301526000611fcb6040830183611ee4565b6060604086015261194f606086018284611f48565b6000604084835280602084015260e08301611ffb8586611dd6565b60a086850152918290529060009061010086015b81831015612033576120218185611e3d565b9284019260019290920191840161200f565b6120406020890189611dd6565b945092507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc091508187820301606088015261207c818585611e69565b93505061208b84880188611ea7565b93508086840301608087015250506120a38183611f91565b9150506120b260608501611cba565b73ffffffffffffffffffffffffffffffffffffffff1660a08401526120d960808501611cba565b73ffffffffffffffffffffffffffffffffffffffff811660c085015250949350505050565b600081518084526020808501945080840160005b8381101561214f578151805173ffffffffffffffffffffffffffffffffffffffff1688528301518388015260409096019590820190600101612112565b509495945050505050565b60005b8381101561217557818101518382015260200161215d565b50506000910152565b6000815180845261219681602086016020860161215a565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60c08152600061012082016121dd8a8b611dd6565b606060c0860152918290529060009061014085015b81831015612217576122048185611e3d565b60409384019360019390930192016121f2565b60208d013560e087015260408d0135610100870152858103602087015261223e818d6120fe565b9350505050612265604084018973ffffffffffffffffffffffffffffffffffffffff169052565b866060840152828103608084015261227d818761217e565b905082810360a0840152612292818587611f48565b9a9950505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff841681526040602082018190528181018390526000908460608401835b868110156122f4576122e48284611e3d565b91830191908301906001016122d2565b50979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa183360301811261239257600080fd5b9190910192915050565b73ffffffffffffffffffffffffffffffffffffffff6123ba82611cba565b1682526020810135602083015260006123d66040830183611ee4565b8082604087013760006040828701015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168601019250505092915050565b60006124278384611dd6565b8360005b828110156124505761243d8285611e3d565b604093840193919091019060010161242b565b5061245e6020870187611dd6565b935091506000905b8382101561248b576124788184611e3d565b6040928301926001929092019101612466565b611a7d6124d16124a7836124a260408c018c611ea7565b61239c565b6124b360608b01611cba565b73ffffffffffffffffffffffffffffffffffffffff16815260200190565b6124b360808a01611cba565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8183360301811261239257600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261254657600080fd5b83018035915067ffffffffffffffff82111561256157600080fd5b602001915036819003821315611bc457600080fd5b60006020828403121561258857600080fd5b81358060030b8114611cfe57600080fd5b6000602082840312156125ab57600080fd5b5051919050565b600080858511156125c257600080fd5b838611156125cf57600080fd5b5050820193919092039150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808201808211156107ce576107ce6125dc565b84868237600085820160008152855161263b818360208a0161215a565b018385823760009301928352509095945050505050565b6000825161239281846020870161215a565b818103818111156107ce576107ce6125dc565b8183823760009101908152919050565b83815260406020820152600061194f604083018486611f48565b73ffffffffffffffffffffffffffffffffffffffff8416815282602082015260606040820152600061194f606083018461217e565b6000602082840312156126e857600080fd5b81518015158114611cfe57600080fd5b602081526000611cfe602083018461217e56fe4f72646572206f72646572294f7264657228496e7075745b5d20696e707574732c4f75747075745b5d206f7574707574732c52656c61792072656c61792c6164647265737320757365722c6164647265737320726563697069656e7429496e707574286164647265737320746f6b656e2c75696e7432353620616d6f756e74294f7574707574286164647265737320746f6b656e2c75696e74323536206d696e4f7574707574416d6f756e742952656c61792861646472657373207461726765742c75696e743235362076616c75652c6279746573206461746129546f6b656e5065726d697373696f6e73286164647265737320746f6b656e2c75696e7432353620616d6f756e7429a2646970667358221220512457ca52bfc529d3aa7b321c2cb9ea86fcc2ba388bc6391744516f029360d164736f6c63430008130033

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

000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3

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

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


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

Validator Index Block Amount
View All Withdrawals

Txn 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.