Contract

0x03C2E2e84031d913d45B1F5b5dDC8E50Fcb28652

Overview

S Balance

Sonic LogoSonic LogoSonic Logo0 S

S Value

-

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

Latest 1 internal transaction

Parent Transaction Hash Block From To
4928612024-12-16 20:37:035 days ago1734381423
0x03C2E2e8...0Fcb28652
 Contract Creation0 S
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
File 1 of 15 : 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 { BytesLib } from "solidity-bytes-utils/contracts/BytesLib.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;
    using BytesLib for bytes;

    /**
     * @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,
                StepToken[] calldata stepTokens
            ) = (step.target, step.value, step.data, step.tokens);

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

            uint256 balance;
            uint256 callDataLength = callData.length;
            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(
                            callData.slice(0, idx),
                            abi.encode(balance),
                            callData.slice(idx + 32, callDataLength - (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 15 : 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 15 : 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 15 : 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 15 : 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 15 : 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 15 : 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 15 : 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 15 : 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 15 : 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 15 : 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 15 : 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 15 : 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 15 : 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);
}

File 15 of 15 : BytesLib.sol
// SPDX-License-Identifier: Unlicense
/*
 * @title Solidity Bytes Arrays Utils
 * @author Gonçalo Sá <[email protected]>
 *
 * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.
 *      The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.
 */
pragma solidity >=0.8.0 <0.9.0;


library BytesLib {
    function concat(
        bytes memory _preBytes,
        bytes memory _postBytes
    )
        internal
        pure
        returns (bytes memory)
    {
        bytes memory tempBytes;

        assembly {
            // Get a location of some free memory and store it in tempBytes as
            // Solidity does for memory variables.
            tempBytes := mload(0x40)

            // Store the length of the first bytes array at the beginning of
            // the memory for tempBytes.
            let length := mload(_preBytes)
            mstore(tempBytes, length)

            // Maintain a memory counter for the current write location in the
            // temp bytes array by adding the 32 bytes for the array length to
            // the starting location.
            let mc := add(tempBytes, 0x20)
            // Stop copying when the memory counter reaches the length of the
            // first bytes array.
            let end := add(mc, length)

            for {
                // Initialize a copy counter to the start of the _preBytes data,
                // 32 bytes into its memory.
                let cc := add(_preBytes, 0x20)
            } lt(mc, end) {
                // Increase both counters by 32 bytes each iteration.
                mc := add(mc, 0x20)
                cc := add(cc, 0x20)
            } {
                // Write the _preBytes data into the tempBytes memory 32 bytes
                // at a time.
                mstore(mc, mload(cc))
            }

            // Add the length of _postBytes to the current length of tempBytes
            // and store it as the new length in the first 32 bytes of the
            // tempBytes memory.
            length := mload(_postBytes)
            mstore(tempBytes, add(length, mload(tempBytes)))

            // Move the memory counter back from a multiple of 0x20 to the
            // actual end of the _preBytes data.
            mc := end
            // Stop copying when the memory counter reaches the new combined
            // length of the arrays.
            end := add(mc, length)

            for {
                let cc := add(_postBytes, 0x20)
            } lt(mc, end) {
                mc := add(mc, 0x20)
                cc := add(cc, 0x20)
            } {
                mstore(mc, mload(cc))
            }

            // Update the free-memory pointer by padding our last write location
            // to 32 bytes: add 31 bytes to the end of tempBytes to move to the
            // next 32 byte block, then round down to the nearest multiple of
            // 32. If the sum of the length of the two arrays is zero then add
            // one before rounding down to leave a blank 32 bytes (the length block with 0).
            mstore(0x40, and(
              add(add(end, iszero(add(length, mload(_preBytes)))), 31),
              not(31) // Round down to the nearest 32 bytes.
            ))
        }

        return tempBytes;
    }

    function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal {
        assembly {
            // Read the first 32 bytes of _preBytes storage, which is the length
            // of the array. (We don't need to use the offset into the slot
            // because arrays use the entire slot.)
            let fslot := sload(_preBytes.slot)
            // Arrays of 31 bytes or less have an even value in their slot,
            // while longer arrays have an odd value. The actual length is
            // the slot divided by two for odd values, and the lowest order
            // byte divided by two for even values.
            // If the slot is even, bitwise and the slot with 255 and divide by
            // two to get the length. If the slot is odd, bitwise and the slot
            // with -1 and divide by two.
            let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
            let mlength := mload(_postBytes)
            let newlength := add(slength, mlength)
            // slength can contain both the length and contents of the array
            // if length < 32 bytes so let's prepare for that
            // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
            switch add(lt(slength, 32), lt(newlength, 32))
            case 2 {
                // Since the new array still fits in the slot, we just need to
                // update the contents of the slot.
                // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length
                sstore(
                    _preBytes.slot,
                    // all the modifications to the slot are inside this
                    // next block
                    add(
                        // we can just add to the slot contents because the
                        // bytes we want to change are the LSBs
                        fslot,
                        add(
                            mul(
                                div(
                                    // load the bytes from memory
                                    mload(add(_postBytes, 0x20)),
                                    // zero all bytes to the right
                                    exp(0x100, sub(32, mlength))
                                ),
                                // and now shift left the number of bytes to
                                // leave space for the length in the slot
                                exp(0x100, sub(32, newlength))
                            ),
                            // increase length by the double of the memory
                            // bytes length
                            mul(mlength, 2)
                        )
                    )
                )
            }
            case 1 {
                // The stored value fits in the slot, but the combined value
                // will exceed it.
                // get the keccak hash to get the contents of the array
                mstore(0x0, _preBytes.slot)
                let sc := add(keccak256(0x0, 0x20), div(slength, 32))

                // save new length
                sstore(_preBytes.slot, add(mul(newlength, 2), 1))

                // The contents of the _postBytes array start 32 bytes into
                // the structure. Our first read should obtain the `submod`
                // bytes that can fit into the unused space in the last word
                // of the stored array. To get this, we read 32 bytes starting
                // from `submod`, so the data we read overlaps with the array
                // contents by `submod` bytes. Masking the lowest-order
                // `submod` bytes allows us to add that value directly to the
                // stored value.

                let submod := sub(32, slength)
                let mc := add(_postBytes, submod)
                let end := add(_postBytes, mlength)
                let mask := sub(exp(0x100, submod), 1)

                sstore(
                    sc,
                    add(
                        and(
                            fslot,
                            0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00
                        ),
                        and(mload(mc), mask)
                    )
                )

                for {
                    mc := add(mc, 0x20)
                    sc := add(sc, 1)
                } lt(mc, end) {
                    sc := add(sc, 1)
                    mc := add(mc, 0x20)
                } {
                    sstore(sc, mload(mc))
                }

                mask := exp(0x100, sub(mc, end))

                sstore(sc, mul(div(mload(mc), mask), mask))
            }
            default {
                // get the keccak hash to get the contents of the array
                mstore(0x0, _preBytes.slot)
                // Start copying to the last used word of the stored array.
                let sc := add(keccak256(0x0, 0x20), div(slength, 32))

                // save new length
                sstore(_preBytes.slot, add(mul(newlength, 2), 1))

                // Copy over the first `submod` bytes of the new data as in
                // case 1 above.
                let slengthmod := mod(slength, 32)
                let mlengthmod := mod(mlength, 32)
                let submod := sub(32, slengthmod)
                let mc := add(_postBytes, submod)
                let end := add(_postBytes, mlength)
                let mask := sub(exp(0x100, submod), 1)

                sstore(sc, add(sload(sc), and(mload(mc), mask)))

                for {
                    sc := add(sc, 1)
                    mc := add(mc, 0x20)
                } lt(mc, end) {
                    sc := add(sc, 1)
                    mc := add(mc, 0x20)
                } {
                    sstore(sc, mload(mc))
                }

                mask := exp(0x100, sub(mc, end))

                sstore(sc, mul(div(mload(mc), mask), mask))
            }
        }
    }

    function slice(
        bytes memory _bytes,
        uint256 _start,
        uint256 _length
    )
        internal
        pure
        returns (bytes memory)
    {
        require(_length + 31 >= _length, "slice_overflow");
        require(_bytes.length >= _start + _length, "slice_outOfBounds");

        bytes memory tempBytes;

        assembly {
            switch iszero(_length)
            case 0 {
                // Get a location of some free memory and store it in tempBytes as
                // Solidity does for memory variables.
                tempBytes := mload(0x40)

                // The first word of the slice result is potentially a partial
                // word read from the original array. To read it, we calculate
                // the length of that partial word and start copying that many
                // bytes into the array. The first word we copy will start with
                // data we don't care about, but the last `lengthmod` bytes will
                // land at the beginning of the contents of the new array. When
                // we're done copying, we overwrite the full first word with
                // the actual length of the slice.
                let lengthmod := and(_length, 31)

                // The multiplication in the next line is necessary
                // because when slicing multiples of 32 bytes (lengthmod == 0)
                // the following copy loop was copying the origin's length
                // and then ending prematurely not copying everything it should.
                let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
                let end := add(mc, _length)

                for {
                    // The multiplication in the next line has the same exact purpose
                    // as the one above.
                    let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
                } lt(mc, end) {
                    mc := add(mc, 0x20)
                    cc := add(cc, 0x20)
                } {
                    mstore(mc, mload(cc))
                }

                mstore(tempBytes, _length)

                //update free-memory pointer
                //allocating the array padded to 32 bytes like the compiler does now
                mstore(0x40, and(add(mc, 31), not(31)))
            }
            //if we want a zero-length slice let's just return a zero-length array
            default {
                tempBytes := mload(0x40)
                //zero out the 32 bytes slice we are about to return
                //we need to do it because Solidity does not garbage collect
                mstore(tempBytes, 0)

                mstore(0x40, add(tempBytes, 0x20))
            }
        }

        return tempBytes;
    }

    function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {
        require(_bytes.length >= _start + 20, "toAddress_outOfBounds");
        address tempAddress;

        assembly {
            tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)
        }

        return tempAddress;
    }

    function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) {
        require(_bytes.length >= _start + 1 , "toUint8_outOfBounds");
        uint8 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x1), _start))
        }

        return tempUint;
    }

    function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) {
        require(_bytes.length >= _start + 2, "toUint16_outOfBounds");
        uint16 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x2), _start))
        }

        return tempUint;
    }

    function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) {
        require(_bytes.length >= _start + 4, "toUint32_outOfBounds");
        uint32 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x4), _start))
        }

        return tempUint;
    }

    function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) {
        require(_bytes.length >= _start + 8, "toUint64_outOfBounds");
        uint64 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x8), _start))
        }

        return tempUint;
    }

    function toUint96(bytes memory _bytes, uint256 _start) internal pure returns (uint96) {
        require(_bytes.length >= _start + 12, "toUint96_outOfBounds");
        uint96 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0xc), _start))
        }

        return tempUint;
    }

    function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) {
        require(_bytes.length >= _start + 16, "toUint128_outOfBounds");
        uint128 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x10), _start))
        }

        return tempUint;
    }

    function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) {
        require(_bytes.length >= _start + 32, "toUint256_outOfBounds");
        uint256 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x20), _start))
        }

        return tempUint;
    }

    function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) {
        require(_bytes.length >= _start + 32, "toBytes32_outOfBounds");
        bytes32 tempBytes32;

        assembly {
            tempBytes32 := mload(add(add(_bytes, 0x20), _start))
        }

        return tempBytes32;
    }

    function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) {
        bool success = true;

        assembly {
            let length := mload(_preBytes)

            // if lengths don't match the arrays are not equal
            switch eq(length, mload(_postBytes))
            case 1 {
                // cb is a circuit breaker in the for loop since there's
                //  no said feature for inline assembly loops
                // cb = 1 - don't breaker
                // cb = 0 - break
                let cb := 1

                let mc := add(_preBytes, 0x20)
                let end := add(mc, length)

                for {
                    let cc := add(_postBytes, 0x20)
                // the next line is the loop condition:
                // while(uint256(mc < end) + cb == 2)
                } eq(add(lt(mc, end), cb), 2) {
                    mc := add(mc, 0x20)
                    cc := add(cc, 0x20)
                } {
                    // if any of these checks fails then arrays are not equal
                    if iszero(eq(mload(mc), mload(cc))) {
                        // unsuccess:
                        success := 0
                        cb := 0
                    }
                }
            }
            default {
                // unsuccess:
                success := 0
            }
        }

        return success;
    }

    function equalStorage(
        bytes storage _preBytes,
        bytes memory _postBytes
    )
        internal
        view
        returns (bool)
    {
        bool success = true;

        assembly {
            // we know _preBytes_offset is 0
            let fslot := sload(_preBytes.slot)
            // Decode the length of the stored array like in concatStorage().
            let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
            let mlength := mload(_postBytes)

            // if lengths don't match the arrays are not equal
            switch eq(slength, mlength)
            case 1 {
                // slength can contain both the length and contents of the array
                // if length < 32 bytes so let's prepare for that
                // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
                if iszero(iszero(slength)) {
                    switch lt(slength, 32)
                    case 1 {
                        // blank the last byte which is the length
                        fslot := mul(div(fslot, 0x100), 0x100)

                        if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) {
                            // unsuccess:
                            success := 0
                        }
                    }
                    default {
                        // cb is a circuit breaker in the for loop since there's
                        //  no said feature for inline assembly loops
                        // cb = 1 - don't breaker
                        // cb = 0 - break
                        let cb := 1

                        // get the keccak hash to get the contents of the array
                        mstore(0x0, _preBytes.slot)
                        let sc := keccak256(0x0, 0x20)

                        let mc := add(_postBytes, 0x20)
                        let end := add(mc, mlength)

                        // the next line is the loop condition:
                        // while(uint256(mc < end) + cb == 2)
                        for {} eq(add(lt(mc, end), cb), 2) {
                            sc := add(sc, 1)
                            mc := add(mc, 0x20)
                        } {
                            if iszero(eq(sload(sc), mload(mc))) {
                                // unsuccess:
                                success := 0
                                cb := 0
                            }
                        }
                    }
                }
            }
            default {
                // unsuccess:
                success := 0
            }
        }

        return success;
    }
}

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"}]

60c06040523480156200001157600080fd5b50604051620032b2380380620032b28339810160408190526200003491620000fa565b6200003f336200009c565b6000805460ff60a01b19169055600180556001600160a01b0381166080526040516200006b90620000ec565b604051809103906000f08015801562000088573d6000803e3d6000fd5b506001600160a01b031660a052506200012c565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6107938062002b1f83390190565b6000602082840312156200010d57600080fd5b81516001600160a01b03811681146200012557600080fd5b9392505050565b60805160a0516129a46200017b600039600081816101310152818161054d01528181610b77015261122401526000818160d30152818161027401528181610b3201526111cf01526129a46000f3fe6080604052600436106100b55760003560e01c8063715018a6116100695780638da5cb5b1161004e5780638da5cb5b146101ef578063f2fde38b1461021a578063f41b2db61461023a57600080fd5b8063715018a6146101c55780638456cb59146101da57600080fd5b80632e0af5e51161009a5780632e0af5e5146101535780633f4ba83a146101755780635c975abb1461018a57600080fd5b806312261ee7146100c15780632a709b141461011f57600080fd5b366100bc57005b600080fd5b3480156100cd57600080fd5b506100f57f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561012b57600080fd5b506100f57f000000000000000000000000000000000000000000000000000000000000000081565b34801561015f57600080fd5b5061017361016e366004611d44565b61024d565b005b34801561018157600080fd5b50610173610393565b34801561019657600080fd5b5060005474010000000000000000000000000000000000000000900460ff166040519015158152602001610116565b3480156101d157600080fd5b506101736103a5565b3480156101e657600080fd5b506101736103b7565b3480156101fb57600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff166100f5565b34801561022657600080fd5b50610173610235366004611e5c565b6103c7565b610173610248366004611e7e565b610483565b6102556105f5565b61025d610668565b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001663fe8ec1a7876102ac6102a78980611ee7565b6106ed565b6102bc60808a0160608b01611e5c565b7fc709880ce3db9deadf408dae85548b37e4530edc88a93e955bd080b45f3255c28a6040516020016102ef929190612159565b60405160208183030381529060405280519060200120604051806101400160405280610109815260200161286661010991398a8a6040518863ffffffff1660e01b8152600401610345979695949392919061233d565b600060405180830381600087803b15801561035f57600080fd5b505af1158015610373573d6000803e3d6000fd5b505050506103828583836107d4565b61038b60018055565b505050505050565b61039b6108a9565b6103a361092a565b565b6103ad6108a9565b6103a360006109a7565b6103bf6108a9565b6103a3610a1c565b6103cf6108a9565b73ffffffffffffffffffffffffffffffffffffffff8116610477576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b610480816109a7565b50565b61048b6105f5565b610493610668565b6104a36080840160608501611e5c565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610536576104e56080840160608501611e5c565b6040517f16cece4800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff909116600482015233602482015260440161046e565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166377fc3fa86105826080860160608701611e5c565b61058c8680611ee7565b6040518463ffffffff1660e01b81526004016105aa93929190612415565b600060405180830381600087803b1580156105c457600080fd5b505af11580156105d8573d6000803e3d6000fd5b505050506105e78383836107d4565b6105f060018055565b505050565b600260015403610661576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161046e565b6002600155565b60005474010000000000000000000000000000000000000000900460ff16156103a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015260640161046e565b60608160008167ffffffffffffffff81111561070b5761070b612475565b60405190808252806020026020018201604052801561075057816020015b60408051808201909152600080825260208201528152602001906001900390816107295790505b50905060005b828110156107c95760405180604001604052803073ffffffffffffffffffffffffffffffffffffffff168152602001878784818110610797576107976124a4565b905060400201602001358152508282815181106107b6576107b66124a4565b6020908102919091010152600101610756565b509150505b92915050565b6107de8282610a8b565b6108146107ee6020850185611ee7565b6107fe60a0870160808801611e5c565b61080b60408801886124d3565b60200135610e77565b61082961082460408501856124d3565b611183565b61083960a0840160808501611e5c565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16846040516108749190612590565b604051908190038120907f1ba5b6ed656994657175705961138c96bd8ec133c35817fa85903f450129e0b190600090a4505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146103a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161046e565b61093261141a565b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b610a24610668565b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861097d3390565b8060005b81811015610e715736848483818110610aaa57610aaa6124a4565b9050602002810190610abc9190612652565b9050600080803681610ad16020870187611e5c565b6020870135610ae36040890189612686565b610af060608b018b611ee7565b955095508080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525094995092975090955050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff90811690871614905080610bc557507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16145b15610c14576040517f781568a400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8616600482015260240161046e565b825160009082825b81811015610dd95736868683818110610c3757610c376124a4565b6040029190910191506000905080610c526020840184611e5c565b610c6260408501602086016126eb565b909250905073ffffffffffffffffffffffffffffffffffffffff8216610c8a57479a50610dcb565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8316906370a0823190602401602060405180830381865afa158015610cf4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d18919061270e565b9650610d25828d8961149e565b60008160030b12610dcb57600381900b610d418b60008361157e565b60408051602081018b905201604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052610da6610d89846020612756565b610d94856020612756565b610d9e908c612769565b8f919061157e565b604051602001610db89392919061277c565b6040516020818303038152906040529a50505b836001019350505050610c1c565b506000808973ffffffffffffffffffffffffffffffffffffffff168989604051610e0391906127bf565b60006040518083038185875af1925050503d8060008114610e40576040519150601f19603f3d011682016040523d82523d6000602084013e610e45565b606091505b509150915081610e5b57610e5b8a8a8a846116f8565b8b6001019b505050505050505050505050610a8f565b50505050565b600083815b8181101561117a5736878783818110610e9757610e976124a4565b6040029190910191506000905080610eb26020840184611e5c565b915050602082013573ffffffffffffffffffffffffffffffffffffffff82166110055747955080861015610f38576040517fd4cf45a200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83166004820152602481018290526044810187905260640161046e565b8686111561100057610f4a8787612769565b955060008873ffffffffffffffffffffffffffffffffffffffff168760405160006040518083038185875af1925050503d8060008114610fa6576040519150601f19603f3d011682016040523d82523d6000602084013e610fab565b606091505b5050905080610ffe576040517f464e254d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a16600482015260240161046e565b505b61111c565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8316906370a0823190602401602060405180830381865afa15801561106f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611093919061270e565b9550808610156110f5576040517fd4cf45a200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83166004820152602481018290526044810187905260640161046e565b851561111c5761111c73ffffffffffffffffffffffffffffffffffffffff83168988611741565b8173ffffffffffffffffffffffffffffffffffffffff167feaf449319c042c9ba3474fa0c5329eb58cd1f23be110cdbf9d697b8d303dac158760405161116491815260200190565b60405180910390a2836001019350505050610e7c565b50505050505050565b60008036816111956020860186611e5c565b60208601356111a76040880188612686565b9296509094509250905073ffffffffffffffffffffffffffffffffffffffff841615611413577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16148061127257507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16145b156112c1576040517f781568a400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015260240161046e565b82471015611304576040517f74c8cbe60000000000000000000000000000000000000000000000000000000081524760048201526024810184905260440161046e565b6000808573ffffffffffffffffffffffffffffffffffffffff1685858560405161132f9291906127d1565b60006040518083038185875af1925050503d806000811461136c576040519150601f19603f3d011682016040523d82523d6000602084013e611371565b606091505b5091509150816113be576113be868686868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508792506116f8915050565b8573ffffffffffffffffffffffffffffffffffffffff167f6c936258f37a22c831493e49cb45429bdf7b6bb0e261f271a15f084e5b08aaff868686604051611408939291906127e1565b60405180910390a250505b5050505050565b60005474010000000000000000000000000000000000000000900460ff166103a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f7420706175736564000000000000000000000000604482015260640161046e565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff838116602483015282919085169063dd62ed3e90604401602060405180830381865afa158015611513573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611537919061270e565b10156105f0576105f073ffffffffffffffffffffffffffffffffffffffff8416837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff611815565b60608161158c81601f612756565b10156115f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f736c6963655f6f766572666c6f77000000000000000000000000000000000000604482015260640161046e565b6115fe8284612756565b84511015611668576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f736c6963655f6f75744f66426f756e6473000000000000000000000000000000604482015260640161046e565b60608215801561168757604051915060008252602082016040526116ef565b6040519150601f8416801560200281840101858101878315602002848b0101015b818310156116c05780518352602092830192016116a8565b5050858452601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016604052505b50949350505050565b8051600003611739578383836040517fe1eec8f100000000000000000000000000000000000000000000000000000000815260040161046e939291906127fb565b805181602001fd5b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526105f09084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152611901565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b3000000000000000000000000000000000000000000000000000000001790526118a18482611a10565b610e715760405173ffffffffffffffffffffffffffffffffffffffff84166024820152600060448201526118fb9085907f095ea7b30000000000000000000000000000000000000000000000000000000090606401611793565b610e7184825b6000611963826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16611ad19092919063ffffffff16565b90508051600014806119845750808060200190518101906119849190612830565b6105f0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840161046e565b60008060008473ffffffffffffffffffffffffffffffffffffffff1684604051611a3a91906127bf565b6000604051808303816000865af19150503d8060008114611a77576040519150601f19603f3d011682016040523d82523d6000602084013e611a7c565b606091505b5091509150818015611aa6575080511580611aa6575080806020019051810190611aa69190612830565b8015611ac8575073ffffffffffffffffffffffffffffffffffffffff85163b15155b95945050505050565b6060611ae08484600085611ae8565b949350505050565b606082471015611b7a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c0000000000000000000000000000000000000000000000000000606482015260840161046e565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051611ba391906127bf565b60006040518083038185875af1925050503d8060008114611be0576040519150601f19603f3d011682016040523d82523d6000602084013e611be5565b606091505b5091509150611bf687838387611c01565b979650505050505050565b60608315611c97578251600003611c905773ffffffffffffffffffffffffffffffffffffffff85163b611c90576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161046e565b5081611ae0565b611ae08383815115611cac5781518083602001fd5b806040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161046e9190612852565b600060a08284031215611cf257600080fd5b50919050565b60008083601f840112611d0a57600080fd5b50813567ffffffffffffffff811115611d2257600080fd5b6020830191508360208260051b8501011115611d3d57600080fd5b9250929050565b60008060008060008060808789031215611d5d57600080fd5b863567ffffffffffffffff80821115611d7557600080fd5b908801906060828b031215611d8957600080fd5b90965060208801359080821115611d9f57600080fd5b611dab8a838b01611ce0565b96506040890135915080821115611dc157600080fd5b818901915089601f830112611dd557600080fd5b813581811115611de457600080fd5b8a6020828501011115611df657600080fd5b602083019650809550506060890135915080821115611e1457600080fd5b50611e2189828a01611cf8565b979a9699509497509295939492505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611e5757600080fd5b919050565b600060208284031215611e6e57600080fd5b611e7782611e33565b9392505050565b600080600060408486031215611e9357600080fd5b833567ffffffffffffffff80821115611eab57600080fd5b611eb787838801611ce0565b94506020860135915080821115611ecd57600080fd5b50611eda86828701611cf8565b9497909650939450505050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112611f1c57600080fd5b83018035915067ffffffffffffffff821115611f3757600080fd5b6020019150600681901b3603821315611d3d57600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112611f8457600080fd5b830160208101925035905067ffffffffffffffff811115611fa457600080fd5b8060061b3603821315611d3d57600080fd5b73ffffffffffffffffffffffffffffffffffffffff611fd482611e33565b168252602090810135910152565b81835260208301925060008160005b84811015612016576120038683611fb6565b6040958601959190910190600101611ff1565b5093949350505050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa183360301811261205457600080fd5b90910192915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261209257600080fd5b830160208101925035905067ffffffffffffffff8111156120b257600080fd5b803603821315611d3d57600080fd5b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b73ffffffffffffffffffffffffffffffffffffffff61212882611e33565b168252602081013560208301526000612144604083018361205d565b60606040860152611ac86060860182846120c1565b6000604084835280602084015260e083016121748586611f4f565b60a086850152918290529060009061010086015b818310156121ac5761219a8185611fb6565b92840192600192909201918401612188565b6121b96020890189611f4f565b945092507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc09150818782030160608801526121f5818585611fe2565b93505061220484880188612020565b935080868403016080870152505061221c818361210a565b91505061222b60608501611e33565b73ffffffffffffffffffffffffffffffffffffffff1660a084015261225260808501611e33565b73ffffffffffffffffffffffffffffffffffffffff811660c08501526116ef565b600081518084526020808501945080840160005b838110156122c4578151805173ffffffffffffffffffffffffffffffffffffffff1688528301518388015260409096019590820190600101612287565b509495945050505050565b60005b838110156122ea5781810151838201526020016122d2565b50506000910152565b6000815180845261230b8160208601602086016122cf565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60c08152600061012082016123528a8b611f4f565b606060c0860152918290529060009061014085015b8183101561238c576123798185611fb6565b6040938401936001939093019201612367565b60208d013560e087015260408d013561010087015285810360208701526123b3818d612273565b93505050506123da604084018973ffffffffffffffffffffffffffffffffffffffff169052565b86606084015282810360808401526123f281876122f3565b905082810360a08401526124078185876120c1565b9a9950505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff841681526040602082018190528181018390526000908460608401835b86811015612469576124598284611fb6565b9183019190830190600101612447565b50979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa183360301811261250757600080fd5b9190910192915050565b73ffffffffffffffffffffffffffffffffffffffff61252f82611e33565b16825260208101356020830152600061254b604083018361205d565b8082604087013760006040828701015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168601019250505092915050565b600061259c8384611f4f565b8360005b828110156125c5576125b28285611fb6565b60409384019391909101906001016125a0565b506125d36020870187611f4f565b935091506000905b83821015612600576125ed8184611fb6565b60409283019260019290920191016125db565b611bf661264661261c8361261760408c018c612020565b612511565b61262860608b01611e33565b73ffffffffffffffffffffffffffffffffffffffff16815260200190565b61262860808a01611e33565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8183360301811261250757600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126126bb57600080fd5b83018035915067ffffffffffffffff8211156126d657600080fd5b602001915036819003821315611d3d57600080fd5b6000602082840312156126fd57600080fd5b81358060030b8114611e7757600080fd5b60006020828403121561272057600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808201808211156107ce576107ce612727565b818103818111156107ce576107ce612727565b6000845161278e8184602089016122cf565b8451908301906127a28183602089016122cf565b84519101906127b58183602088016122cf565b0195945050505050565b600082516125078184602087016122cf565b8183823760009101908152919050565b838152604060208201526000611ac86040830184866120c1565b73ffffffffffffffffffffffffffffffffffffffff84168152826020820152606060408201526000611ac860608301846122f3565b60006020828403121561284257600080fd5b81518015158114611e7757600080fd5b602081526000611e7760208301846122f356fe4f72646572206f72646572294f7264657228496e7075745b5d20696e707574732c4f75747075745b5d206f7574707574732c52656c61792072656c61792c6164647265737320757365722c6164647265737320726563697069656e7429496e707574286164647265737320746f6b656e2c75696e7432353620616d6f756e74294f7574707574286164647265737320746f6b656e2c75696e74323536206d696e4f7574707574416d6f756e742952656c61792861646472657373207461726765742c75696e743235362076616c75652c6279746573206461746129546f6b656e5065726d697373696f6e73286164647265737320746f6b656e2c75696e7432353620616d6f756e7429a2646970667358221220774b3c8fc3f6a631efe5f9b9f7290b86e3d58418e3780b1a7653dd7d895d290564736f6c6343000813003360a060405234801561001057600080fd5b503360805260805161075e610035600039600081816040015260b8015261075e6000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063262d61521461003b57806377fc3fa81461008b575b600080fd5b6100627f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b61009e61009936600461059e565b6100a0565b005b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610116576040517f403e63e90000000000000000000000000000000000000000000000000000000081523360048201526024015b60405180910390fd5b8060005b818110156101b0573684848381811061013557610135610624565b600190940193604002919091019150600090506101556020830183610653565b73ffffffffffffffffffffffffffffffffffffffff1603610176575061011a565b6101aa86336020840180359061018c9086610653565b73ffffffffffffffffffffffffffffffffffffffff169291906101b7565b5061011a565b5050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd0000000000000000000000000000000000000000000000000000000017905261024c908590610252565b50505050565b60006102b4826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166103669092919063ffffffff16565b90508051600014806102d55750808060200190518101906102d59190610675565b610361576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840161010d565b505050565b6060610375848460008561037d565b949350505050565b60608247101561040f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c0000000000000000000000000000000000000000000000000000606482015260840161010d565b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161043891906106bb565b60006040518083038185875af1925050503d8060008114610475576040519150601f19603f3d011682016040523d82523d6000602084013e61047a565b606091505b509150915061048b87838387610496565b979650505050505050565b6060831561052c5782516000036105255773ffffffffffffffffffffffffffffffffffffffff85163b610525576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161010d565b5081610375565b61037583838151156105415781518083602001fd5b806040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161010d91906106d7565b803573ffffffffffffffffffffffffffffffffffffffff8116811461059957600080fd5b919050565b6000806000604084860312156105b357600080fd5b6105bc84610575565b9250602084013567ffffffffffffffff808211156105d957600080fd5b818601915086601f8301126105ed57600080fd5b8135818111156105fc57600080fd5b8760208260061b850101111561061157600080fd5b6020830194508093505050509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561066557600080fd5b61066e82610575565b9392505050565b60006020828403121561068757600080fd5b8151801515811461066e57600080fd5b60005b838110156106b257818101518382015260200161069a565b50506000910152565b600082516106cd818460208701610697565b9190910192915050565b60208152600082518060208401526106f6816040850160208701610697565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea2646970667358221220299c92bc4ed46081b3cb3ce14d83bcb0fa7406938e0e0f750575b6ea4b4c0cf364736f6c63430008130033000000000000000000000000fcf5986450e4a014ffe7ad4ae24921b589d039b5

Deployed Bytecode

0x6080604052600436106100b55760003560e01c8063715018a6116100695780638da5cb5b1161004e5780638da5cb5b146101ef578063f2fde38b1461021a578063f41b2db61461023a57600080fd5b8063715018a6146101c55780638456cb59146101da57600080fd5b80632e0af5e51161009a5780632e0af5e5146101535780633f4ba83a146101755780635c975abb1461018a57600080fd5b806312261ee7146100c15780632a709b141461011f57600080fd5b366100bc57005b600080fd5b3480156100cd57600080fd5b506100f57f000000000000000000000000fcf5986450e4a014ffe7ad4ae24921b589d039b581565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561012b57600080fd5b506100f57f0000000000000000000000005b8f906e9e3355155f05a9c46c5bf3e6d1debe5e81565b34801561015f57600080fd5b5061017361016e366004611d44565b61024d565b005b34801561018157600080fd5b50610173610393565b34801561019657600080fd5b5060005474010000000000000000000000000000000000000000900460ff166040519015158152602001610116565b3480156101d157600080fd5b506101736103a5565b3480156101e657600080fd5b506101736103b7565b3480156101fb57600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff166100f5565b34801561022657600080fd5b50610173610235366004611e5c565b6103c7565b610173610248366004611e7e565b610483565b6102556105f5565b61025d610668565b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000fcf5986450e4a014ffe7ad4ae24921b589d039b51663fe8ec1a7876102ac6102a78980611ee7565b6106ed565b6102bc60808a0160608b01611e5c565b7fc709880ce3db9deadf408dae85548b37e4530edc88a93e955bd080b45f3255c28a6040516020016102ef929190612159565b60405160208183030381529060405280519060200120604051806101400160405280610109815260200161286661010991398a8a6040518863ffffffff1660e01b8152600401610345979695949392919061233d565b600060405180830381600087803b15801561035f57600080fd5b505af1158015610373573d6000803e3d6000fd5b505050506103828583836107d4565b61038b60018055565b505050505050565b61039b6108a9565b6103a361092a565b565b6103ad6108a9565b6103a360006109a7565b6103bf6108a9565b6103a3610a1c565b6103cf6108a9565b73ffffffffffffffffffffffffffffffffffffffff8116610477576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b610480816109a7565b50565b61048b6105f5565b610493610668565b6104a36080840160608501611e5c565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610536576104e56080840160608501611e5c565b6040517f16cece4800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff909116600482015233602482015260440161046e565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000005b8f906e9e3355155f05a9c46c5bf3e6d1debe5e166377fc3fa86105826080860160608701611e5c565b61058c8680611ee7565b6040518463ffffffff1660e01b81526004016105aa93929190612415565b600060405180830381600087803b1580156105c457600080fd5b505af11580156105d8573d6000803e3d6000fd5b505050506105e78383836107d4565b6105f060018055565b505050565b600260015403610661576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161046e565b6002600155565b60005474010000000000000000000000000000000000000000900460ff16156103a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015260640161046e565b60608160008167ffffffffffffffff81111561070b5761070b612475565b60405190808252806020026020018201604052801561075057816020015b60408051808201909152600080825260208201528152602001906001900390816107295790505b50905060005b828110156107c95760405180604001604052803073ffffffffffffffffffffffffffffffffffffffff168152602001878784818110610797576107976124a4565b905060400201602001358152508282815181106107b6576107b66124a4565b6020908102919091010152600101610756565b509150505b92915050565b6107de8282610a8b565b6108146107ee6020850185611ee7565b6107fe60a0870160808801611e5c565b61080b60408801886124d3565b60200135610e77565b61082961082460408501856124d3565b611183565b61083960a0840160808501611e5c565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16846040516108749190612590565b604051908190038120907f1ba5b6ed656994657175705961138c96bd8ec133c35817fa85903f450129e0b190600090a4505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146103a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161046e565b61093261141a565b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b610a24610668565b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861097d3390565b8060005b81811015610e715736848483818110610aaa57610aaa6124a4565b9050602002810190610abc9190612652565b9050600080803681610ad16020870187611e5c565b6020870135610ae36040890189612686565b610af060608b018b611ee7565b955095508080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525094995092975090955050507f000000000000000000000000fcf5986450e4a014ffe7ad4ae24921b589d039b573ffffffffffffffffffffffffffffffffffffffff90811690871614905080610bc557507f0000000000000000000000005b8f906e9e3355155f05a9c46c5bf3e6d1debe5e73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16145b15610c14576040517f781568a400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8616600482015260240161046e565b825160009082825b81811015610dd95736868683818110610c3757610c376124a4565b6040029190910191506000905080610c526020840184611e5c565b610c6260408501602086016126eb565b909250905073ffffffffffffffffffffffffffffffffffffffff8216610c8a57479a50610dcb565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8316906370a0823190602401602060405180830381865afa158015610cf4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d18919061270e565b9650610d25828d8961149e565b60008160030b12610dcb57600381900b610d418b60008361157e565b60408051602081018b905201604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052610da6610d89846020612756565b610d94856020612756565b610d9e908c612769565b8f919061157e565b604051602001610db89392919061277c565b6040516020818303038152906040529a50505b836001019350505050610c1c565b506000808973ffffffffffffffffffffffffffffffffffffffff168989604051610e0391906127bf565b60006040518083038185875af1925050503d8060008114610e40576040519150601f19603f3d011682016040523d82523d6000602084013e610e45565b606091505b509150915081610e5b57610e5b8a8a8a846116f8565b8b6001019b505050505050505050505050610a8f565b50505050565b600083815b8181101561117a5736878783818110610e9757610e976124a4565b6040029190910191506000905080610eb26020840184611e5c565b915050602082013573ffffffffffffffffffffffffffffffffffffffff82166110055747955080861015610f38576040517fd4cf45a200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83166004820152602481018290526044810187905260640161046e565b8686111561100057610f4a8787612769565b955060008873ffffffffffffffffffffffffffffffffffffffff168760405160006040518083038185875af1925050503d8060008114610fa6576040519150601f19603f3d011682016040523d82523d6000602084013e610fab565b606091505b5050905080610ffe576040517f464e254d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a16600482015260240161046e565b505b61111c565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8316906370a0823190602401602060405180830381865afa15801561106f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611093919061270e565b9550808610156110f5576040517fd4cf45a200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83166004820152602481018290526044810187905260640161046e565b851561111c5761111c73ffffffffffffffffffffffffffffffffffffffff83168988611741565b8173ffffffffffffffffffffffffffffffffffffffff167feaf449319c042c9ba3474fa0c5329eb58cd1f23be110cdbf9d697b8d303dac158760405161116491815260200190565b60405180910390a2836001019350505050610e7c565b50505050505050565b60008036816111956020860186611e5c565b60208601356111a76040880188612686565b9296509094509250905073ffffffffffffffffffffffffffffffffffffffff841615611413577f000000000000000000000000fcf5986450e4a014ffe7ad4ae24921b589d039b573ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16148061127257507f0000000000000000000000005b8f906e9e3355155f05a9c46c5bf3e6d1debe5e73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16145b156112c1576040517f781568a400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015260240161046e565b82471015611304576040517f74c8cbe60000000000000000000000000000000000000000000000000000000081524760048201526024810184905260440161046e565b6000808573ffffffffffffffffffffffffffffffffffffffff1685858560405161132f9291906127d1565b60006040518083038185875af1925050503d806000811461136c576040519150601f19603f3d011682016040523d82523d6000602084013e611371565b606091505b5091509150816113be576113be868686868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508792506116f8915050565b8573ffffffffffffffffffffffffffffffffffffffff167f6c936258f37a22c831493e49cb45429bdf7b6bb0e261f271a15f084e5b08aaff868686604051611408939291906127e1565b60405180910390a250505b5050505050565b60005474010000000000000000000000000000000000000000900460ff166103a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f7420706175736564000000000000000000000000604482015260640161046e565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff838116602483015282919085169063dd62ed3e90604401602060405180830381865afa158015611513573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611537919061270e565b10156105f0576105f073ffffffffffffffffffffffffffffffffffffffff8416837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff611815565b60608161158c81601f612756565b10156115f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f736c6963655f6f766572666c6f77000000000000000000000000000000000000604482015260640161046e565b6115fe8284612756565b84511015611668576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f736c6963655f6f75744f66426f756e6473000000000000000000000000000000604482015260640161046e565b60608215801561168757604051915060008252602082016040526116ef565b6040519150601f8416801560200281840101858101878315602002848b0101015b818310156116c05780518352602092830192016116a8565b5050858452601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016604052505b50949350505050565b8051600003611739578383836040517fe1eec8f100000000000000000000000000000000000000000000000000000000815260040161046e939291906127fb565b805181602001fd5b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526105f09084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152611901565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b3000000000000000000000000000000000000000000000000000000001790526118a18482611a10565b610e715760405173ffffffffffffffffffffffffffffffffffffffff84166024820152600060448201526118fb9085907f095ea7b30000000000000000000000000000000000000000000000000000000090606401611793565b610e7184825b6000611963826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16611ad19092919063ffffffff16565b90508051600014806119845750808060200190518101906119849190612830565b6105f0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840161046e565b60008060008473ffffffffffffffffffffffffffffffffffffffff1684604051611a3a91906127bf565b6000604051808303816000865af19150503d8060008114611a77576040519150601f19603f3d011682016040523d82523d6000602084013e611a7c565b606091505b5091509150818015611aa6575080511580611aa6575080806020019051810190611aa69190612830565b8015611ac8575073ffffffffffffffffffffffffffffffffffffffff85163b15155b95945050505050565b6060611ae08484600085611ae8565b949350505050565b606082471015611b7a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c0000000000000000000000000000000000000000000000000000606482015260840161046e565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051611ba391906127bf565b60006040518083038185875af1925050503d8060008114611be0576040519150601f19603f3d011682016040523d82523d6000602084013e611be5565b606091505b5091509150611bf687838387611c01565b979650505050505050565b60608315611c97578251600003611c905773ffffffffffffffffffffffffffffffffffffffff85163b611c90576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161046e565b5081611ae0565b611ae08383815115611cac5781518083602001fd5b806040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161046e9190612852565b600060a08284031215611cf257600080fd5b50919050565b60008083601f840112611d0a57600080fd5b50813567ffffffffffffffff811115611d2257600080fd5b6020830191508360208260051b8501011115611d3d57600080fd5b9250929050565b60008060008060008060808789031215611d5d57600080fd5b863567ffffffffffffffff80821115611d7557600080fd5b908801906060828b031215611d8957600080fd5b90965060208801359080821115611d9f57600080fd5b611dab8a838b01611ce0565b96506040890135915080821115611dc157600080fd5b818901915089601f830112611dd557600080fd5b813581811115611de457600080fd5b8a6020828501011115611df657600080fd5b602083019650809550506060890135915080821115611e1457600080fd5b50611e2189828a01611cf8565b979a9699509497509295939492505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611e5757600080fd5b919050565b600060208284031215611e6e57600080fd5b611e7782611e33565b9392505050565b600080600060408486031215611e9357600080fd5b833567ffffffffffffffff80821115611eab57600080fd5b611eb787838801611ce0565b94506020860135915080821115611ecd57600080fd5b50611eda86828701611cf8565b9497909650939450505050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112611f1c57600080fd5b83018035915067ffffffffffffffff821115611f3757600080fd5b6020019150600681901b3603821315611d3d57600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112611f8457600080fd5b830160208101925035905067ffffffffffffffff811115611fa457600080fd5b8060061b3603821315611d3d57600080fd5b73ffffffffffffffffffffffffffffffffffffffff611fd482611e33565b168252602090810135910152565b81835260208301925060008160005b84811015612016576120038683611fb6565b6040958601959190910190600101611ff1565b5093949350505050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa183360301811261205457600080fd5b90910192915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261209257600080fd5b830160208101925035905067ffffffffffffffff8111156120b257600080fd5b803603821315611d3d57600080fd5b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b73ffffffffffffffffffffffffffffffffffffffff61212882611e33565b168252602081013560208301526000612144604083018361205d565b60606040860152611ac86060860182846120c1565b6000604084835280602084015260e083016121748586611f4f565b60a086850152918290529060009061010086015b818310156121ac5761219a8185611fb6565b92840192600192909201918401612188565b6121b96020890189611f4f565b945092507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc09150818782030160608801526121f5818585611fe2565b93505061220484880188612020565b935080868403016080870152505061221c818361210a565b91505061222b60608501611e33565b73ffffffffffffffffffffffffffffffffffffffff1660a084015261225260808501611e33565b73ffffffffffffffffffffffffffffffffffffffff811660c08501526116ef565b600081518084526020808501945080840160005b838110156122c4578151805173ffffffffffffffffffffffffffffffffffffffff1688528301518388015260409096019590820190600101612287565b509495945050505050565b60005b838110156122ea5781810151838201526020016122d2565b50506000910152565b6000815180845261230b8160208601602086016122cf565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60c08152600061012082016123528a8b611f4f565b606060c0860152918290529060009061014085015b8183101561238c576123798185611fb6565b6040938401936001939093019201612367565b60208d013560e087015260408d013561010087015285810360208701526123b3818d612273565b93505050506123da604084018973ffffffffffffffffffffffffffffffffffffffff169052565b86606084015282810360808401526123f281876122f3565b905082810360a08401526124078185876120c1565b9a9950505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff841681526040602082018190528181018390526000908460608401835b86811015612469576124598284611fb6565b9183019190830190600101612447565b50979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa183360301811261250757600080fd5b9190910192915050565b73ffffffffffffffffffffffffffffffffffffffff61252f82611e33565b16825260208101356020830152600061254b604083018361205d565b8082604087013760006040828701015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168601019250505092915050565b600061259c8384611f4f565b8360005b828110156125c5576125b28285611fb6565b60409384019391909101906001016125a0565b506125d36020870187611f4f565b935091506000905b83821015612600576125ed8184611fb6565b60409283019260019290920191016125db565b611bf661264661261c8361261760408c018c612020565b612511565b61262860608b01611e33565b73ffffffffffffffffffffffffffffffffffffffff16815260200190565b61262860808a01611e33565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8183360301811261250757600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126126bb57600080fd5b83018035915067ffffffffffffffff8211156126d657600080fd5b602001915036819003821315611d3d57600080fd5b6000602082840312156126fd57600080fd5b81358060030b8114611e7757600080fd5b60006020828403121561272057600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808201808211156107ce576107ce612727565b818103818111156107ce576107ce612727565b6000845161278e8184602089016122cf565b8451908301906127a28183602089016122cf565b84519101906127b58183602088016122cf565b0195945050505050565b600082516125078184602087016122cf565b8183823760009101908152919050565b838152604060208201526000611ac86040830184866120c1565b73ffffffffffffffffffffffffffffffffffffffff84168152826020820152606060408201526000611ac860608301846122f3565b60006020828403121561284257600080fd5b81518015158114611e7757600080fd5b602081526000611e7760208301846122f356fe4f72646572206f72646572294f7264657228496e7075745b5d20696e707574732c4f75747075745b5d206f7574707574732c52656c61792072656c61792c6164647265737320757365722c6164647265737320726563697069656e7429496e707574286164647265737320746f6b656e2c75696e7432353620616d6f756e74294f7574707574286164647265737320746f6b656e2c75696e74323536206d696e4f7574707574416d6f756e742952656c61792861646472657373207461726765742c75696e743235362076616c75652c6279746573206461746129546f6b656e5065726d697373696f6e73286164647265737320746f6b656e2c75696e7432353620616d6f756e7429a2646970667358221220774b3c8fc3f6a631efe5f9b9f7290b86e3d58418e3780b1a7653dd7d895d290564736f6c63430008130033

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

000000000000000000000000fcf5986450e4a014ffe7ad4ae24921b589d039b5

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

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000fcf5986450e4a014ffe7ad4ae24921b589d039b5


Block Transaction Gas Used Reward
view all blocks produced

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

Validator Index Block Amount
View All Withdrawals

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

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.