HYPE Price: $23.52 (+4.17%)
 

Overview

HYPE Balance

HyperEVM LogoHyperEVM LogoHyperEVM Logo0 HYPE

HYPE Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To
Execute Order254202352026-01-24 12:24:079 hrs ago1769257447IN
0x8E304661...999ea6B5d
0 HYPE0.000460890.8453
Execute Order246412362026-01-15 15:30:489 days ago1768491048IN
0x8E304661...999ea6B5d
0 HYPE0.003470995.77031428
Execute Order243635812026-01-12 11:39:0412 days ago1768217944IN
0x8E304661...999ea6B5d
0 HYPE0.002780755.1
Execute Order243161802026-01-11 22:42:0012 days ago1768171320IN
0x8E304661...999ea6B5d
0 HYPE0.00167321.491
Execute Order242262902026-01-10 22:08:2413 days ago1768082904IN
0x8E304661...999ea6B5d
0 HYPE0.000006850.1
Execute Order240971672026-01-09 10:51:3815 days ago1767955898IN
0x8E304661...999ea6B5d
0 HYPE0.001145012.1
Execute Order240090252026-01-08 10:46:4116 days ago1767869201IN
0x8E304661...999ea6B5d
0 HYPE0.000160570.2375
Execute Order239532182026-01-07 19:31:4917 days ago1767814309IN
0x8E304661...999ea6B5d
0 HYPE0.000090350.15022716
Execute Order239531932026-01-07 19:31:2417 days ago1767814284IN
0x8E304661...999ea6B5d
0 HYPE0.000060740.101
Execute Order239520992026-01-07 19:13:2817 days ago1767813208IN
0x8E304661...999ea6B5d
0 HYPE0.000021770.32227443
Execute Order239520812026-01-07 19:13:1017 days ago1767813190IN
0x8E304661...999ea6B5d
0 HYPE0.000040560.60029503
Execute Order239520672026-01-07 19:12:5717 days ago1767813177IN
0x8E304661...999ea6B5d
0 HYPE0.000007240.1072502
Execute Order239520472026-01-07 19:12:3717 days ago1767813157IN
0x8E304661...999ea6B5d
0 HYPE0.000060150.1
Execute Order238954082026-01-07 3:44:0617 days ago1767757446IN
0x8E304661...999ea6B5d
0 HYPE0.000571741
Execute Order236696042026-01-04 14:02:2420 days ago1767535344IN
0x8E304661...999ea6B5d
0 HYPE0.0001450.21833683
Execute Order235767252026-01-03 12:39:4821 days ago1767443988IN
0x8E304661...999ea6B5d
0 HYPE0.000214530.36974819
Execute Order235766992026-01-03 12:39:2221 days ago1767443962IN
0x8E304661...999ea6B5d
0 HYPE0.0002814.66738582
Execute Order235766732026-01-03 12:38:5721 days ago1767443937IN
0x8E304661...999ea6B5d
0 HYPE0.004554147.08155819
Execute Order231484712025-12-29 15:37:5426 days ago1767022674IN
0x8E304661...999ea6B5d
0 HYPE0.001148921.83822854
Execute Order229640762025-12-27 13:15:0028 days ago1766841300IN
0x8E304661...999ea6B5d
0 HYPE0.00010710.17508753
Execute Order227839432025-12-25 12:02:0030 days ago1766664120IN
0x8E304661...999ea6B5d
0 HYPE0.00020950.34695507
Execute Order220927572025-12-17 15:09:4038 days ago1765984180IN
0x8E304661...999ea6B5d
0 HYPE0.00371845.61390542
Execute Order220890632025-12-17 14:09:0638 days ago1765980546IN
0x8E304661...999ea6B5d
0 HYPE0.000064820.109841
Execute Order220882622025-12-17 13:55:5938 days ago1765979759IN
0x8E304661...999ea6B5d
0 HYPE0.000060670.11001
Execute Order220882442025-12-17 13:55:4138 days ago1765979741IN
0x8E304661...999ea6B5d
0 HYPE0.000070070.11159585
View all transactions

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Block From To
42211392025-05-23 17:31:00246 days ago1748021460
0x8E304661...999ea6B5d
 Contract Creation0 HYPE
Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
BeefyZapRouter

Compiler Version
v0.8.21+commit.d9974bed

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion
// SPDX-License-Identifier: MIT

pragma solidity 0.8.21;

import { SafeERC20, IERC20 } from "@openzeppelin-5/contracts/token/ERC20/utils/SafeERC20.sol";
import { Ownable } from "@openzeppelin-5/contracts/access/Ownable.sol";
import { Pausable } from "@openzeppelin-5/contracts/utils/Pausable.sol";
import { ReentrancyGuard } from "@openzeppelin-5/contracts/utils/ReentrancyGuard.sol";
import { BytesLib } from "./libs/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) Ownable(msg.sender) {
        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 {}
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {Context} from "../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.
 *
 * The initial owner is set to the address provided by the deployer. 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;

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

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

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @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 {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @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 {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _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);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @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 value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

    /**
     * @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens 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 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` 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 value) external returns (bool);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.20;

/**
 * @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.
 *
 * ==== Security Considerations
 *
 * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
 * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
 * considered as an intention to spend the allowance in any specific way. The second is that because permits have
 * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
 * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
 * generally recommended is:
 *
 * ```solidity
 * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
 *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
 *     doThing(..., value);
 * }
 *
 * function doThing(..., uint256 value) public {
 *     token.safeTransferFrom(msg.sender, address(this), value);
 *     ...
 * }
 * ```
 *
 * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
 * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
 * {SafeERC20-safeTransferFrom}).
 *
 * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
 * contracts should have entry points that don't rely on permit.
 */
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].
     *
     * CAUTION: See Security Considerations above.
     */
    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);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";

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

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

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

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

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

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

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

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

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

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

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

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

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)

pragma solidity ^0.8.20;

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

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

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

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

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

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason or custom error, it is bubbled
     * up by this function (like regular Solidity function calls). However, if
     * the call reverted with no returned reason, this function reverts with a
     * {FailedInnerCall} error.
     *
     * 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.
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0);
    }

    /**
     * @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`.
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        if (address(this).balance < value) {
            revert AddressInsufficientBalance(address(this));
        }
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

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

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

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
     * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
     * unsuccessful call.
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata
    ) internal view returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            // only check if target is a contract if the call was successful and the return data is empty
            // otherwise we already know that it was a contract
            if (returndata.length == 0 && target.code.length == 0) {
                revert AddressEmptyCode(target);
            }
            return returndata;
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
     * revert reason or with a default {FailedInnerCall} error.
     */
    function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            return returndata;
        }
    }

    /**
     * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
     */
    function _revert(bytes memory returndata) 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 FailedInnerCall();
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

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

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Pausable.sol)

pragma solidity ^0.8.20;

import {Context} from "../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 {
    bool private _paused;

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

    /**
     * @dev The operation failed because the contract is paused.
     */
    error EnforcedPause();

    /**
     * @dev The operation failed because the contract is not paused.
     */
    error ExpectedPause();

    /**
     * @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 {
        if (paused()) {
            revert EnforcedPause();
        }
    }

    /**
     * @dev Throws if the contract is not paused.
     */
    function _requirePaused() internal view virtual {
        if (!paused()) {
            revert ExpectedPause();
        }
    }

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)

pragma solidity ^0.8.20;

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

    /**
     * @dev Unauthorized reentrant call.
     */
    error ReentrancyGuardReentrantCall();

    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
        if (_status == ENTERED) {
            revert ReentrancyGuardReentrantCall();
        }

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

// SPDX-License-Identifier: MIT

pragma solidity 0.8.21;

import { SafeERC20, IERC20 } from "@openzeppelin-5/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 11 of 15 : ZapErrors.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.21;

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

// SPDX-License-Identifier: MIT

pragma solidity 0.8.21;

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

// SPDX-License-Identifier: MIT

pragma solidity 0.8.21;

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

// SPDX-License-Identifier: MIT

pragma solidity 0.8.21;

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

// 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
{
  "evmVersion": "paris",
  "libraries": {},
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_permit2","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[{"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":[],"name":"EnforcedPause","type":"error"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"}],"name":"EtherTransferFailed","type":"error"},{"inputs":[],"name":"ExpectedPause","type":"error"},{"inputs":[],"name":"FailedInnerCall","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":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","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"}]

60c06040523480156200001157600080fd5b506040516200257238038062002572833981016040819052620000349162000122565b33806200005b57604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b6200006681620000c4565b506000805460ff60a01b19169055600180556001600160a01b038116608052604051620000939062000114565b604051809103906000f080158015620000b0573d6000803e3d6000fd5b506001600160a01b031660a0525062000154565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6104f8806200207a83390190565b6000602082840312156200013557600080fd5b81516001600160a01b03811681146200014d57600080fd5b9392505050565b60805160a051611ed7620001a3600039600081816101040152818161042f015281816108b50152610dd101526000818160b30152818161021c0152818161087d0152610d960152611ed76000f3fe6080604052600436106100955760003560e01c8063715018a611610059578063715018a6146101875780638456cb591461019c5780638da5cb5b146101b1578063f2fde38b146101cf578063f41b2db6146101ef57600080fd5b806312261ee7146100a15780632a709b14146100f25780632e0af5e5146101265780633f4ba83a146101485780635c975abb1461015d57600080fd5b3661009c57005b600080fd5b3480156100ad57600080fd5b506100d57f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156100fe57600080fd5b506100d57f000000000000000000000000000000000000000000000000000000000000000081565b34801561013257600080fd5b506101466101413660046114ad565b610202565b005b34801561015457600080fd5b5061014661033b565b34801561016957600080fd5b50600054600160a01b900460ff1660405190151581526020016100e9565b34801561019357600080fd5b5061014661034d565b3480156101a857600080fd5b5061014661035f565b3480156101bd57600080fd5b506000546001600160a01b03166100d5565b3480156101db57600080fd5b506101466101ea3660046115b8565b61036f565b6101466101fd3660046115d3565b6103b2565b61020a6104d7565b610212610501565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663fe8ec1a78761025461024f898061163c565b61052c565b61026460808a0160608b016115b8565b7fc709880ce3db9deadf408dae85548b37e4530edc88a93e955bd080b45f3255c28a6040516020016102979291906117fc565b604051602081830303815290604052805190602001206040518061014001604052806101098152602001611d9961010991398a8a6040518863ffffffff1660e01b81526004016102ed979695949392919061197d565b600060405180830381600087803b15801561030757600080fd5b505af115801561031b573d6000803e3d6000fd5b5050505061032a858383610606565b61033360018055565b505050505050565b6103436106c1565b61034b6106ee565b565b6103556106c1565b61034b6000610743565b6103676106c1565b61034b610793565b6103776106c1565b6001600160a01b0381166103a657604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b6103af81610743565b50565b6103ba6104d7565b6103c2610501565b6103d260808401606085016115b8565b6001600160a01b0316336001600160a01b031614610425576103fa60808401606085016115b8565b6040516302d9d9c960e31b81526001600160a01b03909116600482015233602482015260440161039d565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166377fc3fa861046460808601606087016115b8565b61046e868061163c565b6040518463ffffffff1660e01b815260040161048c93929190611a48565b600060405180830381600087803b1580156104a657600080fd5b505af11580156104ba573d6000803e3d6000fd5b505050506104c9838383610606565b6104d260018055565b505050565b6002600154036104fa57604051633ee5aeb560e01b815260040160405180910390fd5b6002600155565b600054600160a01b900460ff161561034b5760405163d93c066560e01b815260040160405180910390fd5b60608160008167ffffffffffffffff81111561054a5761054a611a9b565b60405190808252806020026020018201604052801561058f57816020015b60408051808201909152600080825260208201528152602001906001900390816105685790505b50905060005b828110156105fb576040518060400160405280306001600160a01b031681526020018787848181106105c9576105c9611ab1565b905060400201602001358152508282815181106105e8576105e8611ab1565b6020908102919091010152600101610595565b509150505b92915050565b61061082826107d6565b610646610620602085018561163c565b61063060a08701608088016115b8565b61063d6040880188611ac7565b60200135610b17565b61065b6106566040850185611ac7565b610d57565b61066b60a08401608085016115b8565b6001600160a01b0316336001600160a01b03168460405161068c9190611b3b565b604051908190038120907f1ba5b6ed656994657175705961138c96bd8ec133c35817fa85903f450129e0b190600090a4505050565b6000546001600160a01b0316331461034b5760405163118cdaa760e01b815233600482015260240161039d565b6106f6610f54565b6000805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b61079b610501565b6000805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586107263390565b8060005b81811015610b1157368484838181106107f5576107f5611ab1565b90506020028101906108079190611bfb565b905060008080368161081c60208701876115b8565b602087013561082e6040890189611c11565b61083b60608b018b61163c565b955095508080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525094995092975090955050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03908116908716149050806108e957507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316856001600160a01b0316145b1561091257604051631e055a2960e21b81526001600160a01b038616600482015260240161039d565b825160009082825b81811015610a86573686868381811061093557610935611ab1565b604002919091019150600090508061095060208401846115b8565b6109606040850160208601611c58565b90925090506001600160a01b03821661097b57479a50610a78565b6040516370a0823160e01b81523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa1580156109bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109e39190611c7b565b96506109f0828d89610f7e565b60008160030b12610a7857600381900b610a0c8b60008361100d565b60408051602081018b90520160408051601f19818403018152919052610a53610a36846020611caa565b610a41856020611caa565b610a4b908c611cbd565b8f919061100d565b604051602001610a6593929190611cd0565b6040516020818303038152906040529a50505b83600101935050505061091a565b50600080896001600160a01b03168989604051610aa39190611d13565b60006040518083038185875af1925050503d8060008114610ae0576040519150601f19603f3d011682016040523d82523d6000602084013e610ae5565b606091505b509150915081610afb57610afb8a8a8a8461111c565b8b6001019b5050505050505050505050506107da565b50505050565b600083815b81811015610d4e5736878783818110610b3757610b37611ab1565b6040029190910191506000905080610b5260208401846115b8565b91505060208201356001600160a01b038216610c3f5747955080861015610ba557604051636a67a2d160e11b81526001600160a01b0383166004820152602481018290526044810187905260640161039d565b86861115610c3a57610bb78787611cbd565b95506000886001600160a01b03168760405160006040518083038185875af1925050503d8060008114610c06576040519150601f19603f3d011682016040523d82523d6000602084013e610c0b565b606091505b5050905080610c385760405163464e254d60e01b81526001600160a01b038a16600482015260240161039d565b505b610cfd565b6040516370a0823160e01b81523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa158015610c83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca79190611c7b565b955080861015610ce357604051636a67a2d160e11b81526001600160a01b0383166004820152602481018290526044810187905260640161039d565b8515610cfd57610cfd6001600160a01b038316898861114c565b816001600160a01b03167feaf449319c042c9ba3474fa0c5329eb58cd1f23be110cdbf9d697b8d303dac1587604051610d3891815260200190565b60405180910390a2836001019350505050610b1c565b50505050505050565b6000803681610d6960208601866115b8565b6020860135610d7b6040880188611c11565b929650909450925090506001600160a01b03841615610f4d577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b03161480610e0557507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b0316145b15610e2e57604051631e055a2960e21b81526001600160a01b038516600482015260240161039d565b82471015610e5857604051633a6465f360e11b81524760048201526024810184905260440161039d565b600080856001600160a01b0316858585604051610e76929190611d25565b60006040518083038185875af1925050503d8060008114610eb3576040519150601f19603f3d011682016040523d82523d6000602084013e610eb8565b606091505b509150915081610f0557610f05868686868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525087925061111c915050565b856001600160a01b03167f6c936258f37a22c831493e49cb45429bdf7b6bb0e261f271a15f084e5b08aaff868686604051610f4293929190611d35565b60405180910390a250505b5050505050565b600054600160a01b900460ff1661034b57604051638dfc202b60e01b815260040160405180910390fd5b604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015282919085169063dd62ed3e90604401602060405180830381865afa158015610fcd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ff19190611c7b565b10156104d2576104d26001600160a01b038416836000196111ab565b60608161101b81601f611caa565b101561105a5760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b604482015260640161039d565b6110648284611caa565b845110156110a85760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b604482015260640161039d565b6060821580156110c75760405191506000825260208201604052611111565b6040519150601f8416801560200281840101858101878315602002848b0101015b818310156111005780518352602092830192016110e8565b5050858452601f01601f1916604052505b5090505b9392505050565b80516000036111445783838360405163e1eec8f160e01b815260040161039d93929190611d4f565b805181602001fd5b6040516001600160a01b038381166024830152604482018390526104d291859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050611237565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b1790526111fc848261129a565b610b11576040516001600160a01b0384811660248301526000604483015261123191869182169063095ea7b390606401611179565b610b1184825b600061124c6001600160a01b03841683611342565b9050805160001415801561127157508080602001905181019061126f9190611d76565b155b156104d257604051635274afe760e01b81526001600160a01b038416600482015260240161039d565b6000806000846001600160a01b0316846040516112b79190611d13565b6000604051808303816000865af19150503d80600081146112f4576040519150601f19603f3d011682016040523d82523d6000602084013e6112f9565b606091505b50915091508180156113235750805115806113235750808060200190518101906113239190611d76565b801561133957506000856001600160a01b03163b115b95945050505050565b60606111158383600084600080856001600160a01b031684866040516113689190611d13565b60006040518083038185875af1925050503d80600081146113a5576040519150601f19603f3d011682016040523d82523d6000602084013e6113aa565b606091505b50915091506113ba8683836113c4565b9695505050505050565b6060826113d9576113d482611420565b611115565b81511580156113f057506001600160a01b0384163b155b1561141957604051639996b31560e01b81526001600160a01b038516600482015260240161039d565b5080611115565b8051156114305780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b600060a0828403121561145b57600080fd5b50919050565b60008083601f84011261147357600080fd5b50813567ffffffffffffffff81111561148b57600080fd5b6020830191508360208260051b85010111156114a657600080fd5b9250929050565b600080600080600080608087890312156114c657600080fd5b863567ffffffffffffffff808211156114de57600080fd5b908801906060828b0312156114f257600080fd5b9096506020880135908082111561150857600080fd5b6115148a838b01611449565b9650604089013591508082111561152a57600080fd5b818901915089601f83011261153e57600080fd5b81358181111561154d57600080fd5b8a602082850101111561155f57600080fd5b60208301965080955050606089013591508082111561157d57600080fd5b5061158a89828a01611461565b979a9699509497509295939492505050565b80356001600160a01b03811681146115b357600080fd5b919050565b6000602082840312156115ca57600080fd5b6111158261159c565b6000806000604084860312156115e857600080fd5b833567ffffffffffffffff8082111561160057600080fd5b61160c87838801611449565b9450602086013591508082111561162257600080fd5b5061162f86828701611461565b9497909650939450505050565b6000808335601e1984360301811261165357600080fd5b83018035915067ffffffffffffffff82111561166e57600080fd5b6020019150600681901b36038213156114a657600080fd5b6000808335601e1984360301811261169d57600080fd5b830160208101925035905067ffffffffffffffff8111156116bd57600080fd5b8060061b36038213156114a657600080fd5b6001600160a01b036116e08261159c565b168252602090810135910152565b81835260208301925060008160005b848110156117225761170f86836116cf565b60409586019591909101906001016116fd565b5093949350505050565b60008235605e1983360301811261174257600080fd5b90910192915050565b6000808335601e1984360301811261176257600080fd5b830160208101925035905067ffffffffffffffff81111561178257600080fd5b8036038213156114a657600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6001600160a01b036117cb8261159c565b1682526020810135602083015260006117e7604083018361174b565b60606040860152611339606086018284611791565b6000604084835280602084015260e083016118178586611686565b60a086850152918290529060009061010086015b8183101561184f5761183d81856116cf565b9284019260019290920191840161182b565b61185c6020890189611686565b94509250603f1991508187820301606088015261187a8185856116ee565b9350506118898488018861172c565b93508086840301608087015250506118a181836117ba565b9150506118b06060850161159c565b6001600160a01b031660a08401526118ca6080850161159c565b6001600160a01b03811660c0850152611111565b600081518084526020808501945080840160005b8381101561192257815180516001600160a01b0316885283015183880152604090960195908201906001016118f2565b509495945050505050565b60005b83811015611948578181015183820152602001611930565b50506000910152565b6000815180845261196981602086016020860161192d565b601f01601f19169290920160200192915050565b60c08152600061012082016119928a8b611686565b606060c0860152918290529060009061014085015b818310156119cc576119b981856116cf565b60409384019360019390930192016119a7565b60208d013560e087015260408d013561010087015285810360208701526119f3818d6118de565b9350505050611a0d60408401896001600160a01b03169052565b8660608401528281036080840152611a258187611951565b905082810360a0840152611a3a818587611791565b9a9950505050505050505050565b6001600160a01b03841681526040602082018190528181018390526000908460608401835b86811015611a8f57611a7f82846116cf565b9183019190830190600101611a6d565b50979650505050505050565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b60008235605e19833603018112611add57600080fd5b9190910192915050565b6001600160a01b03611af88261159c565b168252602081013560208301526000611b14604083018361174b565b808260408701376000604082870101526040601f19601f8301168601019250505092915050565b6000611b478384611686565b8360005b82811015611b7057611b5d82856116cf565b6040938401939190910190600101611b4b565b50611b7e6020870187611686565b935091506000905b83821015611bab57611b9881846116cf565b6040928301926001929092019101611b86565b611bf0611be4611bc783611bc260408c018c61172c565b611ae7565b611bd360608b0161159c565b6001600160a01b0316815260200190565b611bd360808a0161159c565b979650505050505050565b60008235607e19833603018112611add57600080fd5b6000808335601e19843603018112611c2857600080fd5b83018035915067ffffffffffffffff821115611c4357600080fd5b6020019150368190038213156114a657600080fd5b600060208284031215611c6a57600080fd5b81358060030b811461111557600080fd5b600060208284031215611c8d57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561060057610600611c94565b8181038181111561060057610600611c94565b60008451611ce281846020890161192d565b845190830190611cf681836020890161192d565b8451910190611d0981836020880161192d565b0195945050505050565b60008251611add81846020870161192d565b8183823760009101908152919050565b838152604060208201526000611339604083018486611791565b60018060a01b03841681528260208201526060604082015260006113396060830184611951565b600060208284031215611d8857600080fd5b8151801515811461111557600080fdfe4f72646572206f72646572294f7264657228496e7075745b5d20696e707574732c4f75747075745b5d206f7574707574732c52656c61792072656c61792c6164647265737320757365722c6164647265737320726563697069656e7429496e707574286164647265737320746f6b656e2c75696e7432353620616d6f756e74294f7574707574286164647265737320746f6b656e2c75696e74323536206d696e4f7574707574416d6f756e742952656c61792861646472657373207461726765742c75696e743235362076616c75652c6279746573206461746129546f6b656e5065726d697373696f6e73286164647265737320746f6b656e2c75696e7432353620616d6f756e7429a264697066735822122064429d1084d8ed3c74ad89ca0e52812c4d2f1007936fb2b4f7b34f5d9ea532cd64736f6c6343000815003360a060405234801561001057600080fd5b50336080526080516104c36100356000396000818160400152609e01526104c36000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063262d61521461003b57806377fc3fa81461007e575b600080fd5b6100627f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200160405180910390f35b61009161008c366004610385565b610093565b005b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146100e35760405163403e63e960e01b81523360048201526024015b60405180910390fd5b8060005b8181101561016357368484838181106101025761010261040b565b600190940193604002919091019150600090506101226020830183610421565b6001600160a01b03160361013657506100e7565b61015d86336020840180359061014c9086610421565b6001600160a01b031692919061016a565b506100e7565b5050505050565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b1790526101c49085906101ca565b50505050565b60006101df6001600160a01b03841683610232565b90508051600014158015610204575080806020019051810190610202919061043c565b155b1561022d57604051635274afe760e01b81526001600160a01b03841660048201526024016100da565b505050565b606061024083836000610247565b9392505050565b60608147101561026c5760405163cd78605960e01b81523060048201526024016100da565b600080856001600160a01b03168486604051610288919061045e565b60006040518083038185875af1925050503d80600081146102c5576040519150601f19603f3d011682016040523d82523d6000602084013e6102ca565b606091505b50915091506102da8683836102e4565b9695505050505050565b6060826102f9576102f482610340565b610240565b815115801561031057506001600160a01b0384163b155b1561033957604051639996b31560e01b81526001600160a01b03851660048201526024016100da565b5080610240565b8051156103505780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b80356001600160a01b038116811461038057600080fd5b919050565b60008060006040848603121561039a57600080fd5b6103a384610369565b9250602084013567ffffffffffffffff808211156103c057600080fd5b818601915086601f8301126103d457600080fd5b8135818111156103e357600080fd5b8760208260061b85010111156103f857600080fd5b6020830194508093505050509250925092565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561043357600080fd5b61024082610369565b60006020828403121561044e57600080fd5b8151801515811461024057600080fd5b6000825160005b8181101561047f5760208186018101518583015201610465565b50600092019182525091905056fea2646970667358221220ec681759d9393abf684e64f1d01b0775812f981e1294d28217fd99ba116e320964736f6c634300081500330000000000000000000000000000000000000000000000000000000000000000

Deployed Bytecode

0x6080604052600436106100955760003560e01c8063715018a611610059578063715018a6146101875780638456cb591461019c5780638da5cb5b146101b1578063f2fde38b146101cf578063f41b2db6146101ef57600080fd5b806312261ee7146100a15780632a709b14146100f25780632e0af5e5146101265780633f4ba83a146101485780635c975abb1461015d57600080fd5b3661009c57005b600080fd5b3480156100ad57600080fd5b506100d57f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156100fe57600080fd5b506100d57f00000000000000000000000064d44293eadeac464684b06bbc2e1f71042ea98681565b34801561013257600080fd5b506101466101413660046114ad565b610202565b005b34801561015457600080fd5b5061014661033b565b34801561016957600080fd5b50600054600160a01b900460ff1660405190151581526020016100e9565b34801561019357600080fd5b5061014661034d565b3480156101a857600080fd5b5061014661035f565b3480156101bd57600080fd5b506000546001600160a01b03166100d5565b3480156101db57600080fd5b506101466101ea3660046115b8565b61036f565b6101466101fd3660046115d3565b6103b2565b61020a6104d7565b610212610501565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663fe8ec1a78761025461024f898061163c565b61052c565b61026460808a0160608b016115b8565b7fc709880ce3db9deadf408dae85548b37e4530edc88a93e955bd080b45f3255c28a6040516020016102979291906117fc565b604051602081830303815290604052805190602001206040518061014001604052806101098152602001611d9961010991398a8a6040518863ffffffff1660e01b81526004016102ed979695949392919061197d565b600060405180830381600087803b15801561030757600080fd5b505af115801561031b573d6000803e3d6000fd5b5050505061032a858383610606565b61033360018055565b505050505050565b6103436106c1565b61034b6106ee565b565b6103556106c1565b61034b6000610743565b6103676106c1565b61034b610793565b6103776106c1565b6001600160a01b0381166103a657604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b6103af81610743565b50565b6103ba6104d7565b6103c2610501565b6103d260808401606085016115b8565b6001600160a01b0316336001600160a01b031614610425576103fa60808401606085016115b8565b6040516302d9d9c960e31b81526001600160a01b03909116600482015233602482015260440161039d565b6001600160a01b037f00000000000000000000000064d44293eadeac464684b06bbc2e1f71042ea986166377fc3fa861046460808601606087016115b8565b61046e868061163c565b6040518463ffffffff1660e01b815260040161048c93929190611a48565b600060405180830381600087803b1580156104a657600080fd5b505af11580156104ba573d6000803e3d6000fd5b505050506104c9838383610606565b6104d260018055565b505050565b6002600154036104fa57604051633ee5aeb560e01b815260040160405180910390fd5b6002600155565b600054600160a01b900460ff161561034b5760405163d93c066560e01b815260040160405180910390fd5b60608160008167ffffffffffffffff81111561054a5761054a611a9b565b60405190808252806020026020018201604052801561058f57816020015b60408051808201909152600080825260208201528152602001906001900390816105685790505b50905060005b828110156105fb576040518060400160405280306001600160a01b031681526020018787848181106105c9576105c9611ab1565b905060400201602001358152508282815181106105e8576105e8611ab1565b6020908102919091010152600101610595565b509150505b92915050565b61061082826107d6565b610646610620602085018561163c565b61063060a08701608088016115b8565b61063d6040880188611ac7565b60200135610b17565b61065b6106566040850185611ac7565b610d57565b61066b60a08401608085016115b8565b6001600160a01b0316336001600160a01b03168460405161068c9190611b3b565b604051908190038120907f1ba5b6ed656994657175705961138c96bd8ec133c35817fa85903f450129e0b190600090a4505050565b6000546001600160a01b0316331461034b5760405163118cdaa760e01b815233600482015260240161039d565b6106f6610f54565b6000805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b61079b610501565b6000805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586107263390565b8060005b81811015610b1157368484838181106107f5576107f5611ab1565b90506020028101906108079190611bfb565b905060008080368161081c60208701876115b8565b602087013561082e6040890189611c11565b61083b60608b018b61163c565b955095508080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525094995092975090955050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03908116908716149050806108e957507f00000000000000000000000064d44293eadeac464684b06bbc2e1f71042ea9866001600160a01b0316856001600160a01b0316145b1561091257604051631e055a2960e21b81526001600160a01b038616600482015260240161039d565b825160009082825b81811015610a86573686868381811061093557610935611ab1565b604002919091019150600090508061095060208401846115b8565b6109606040850160208601611c58565b90925090506001600160a01b03821661097b57479a50610a78565b6040516370a0823160e01b81523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa1580156109bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109e39190611c7b565b96506109f0828d89610f7e565b60008160030b12610a7857600381900b610a0c8b60008361100d565b60408051602081018b90520160408051601f19818403018152919052610a53610a36846020611caa565b610a41856020611caa565b610a4b908c611cbd565b8f919061100d565b604051602001610a6593929190611cd0565b6040516020818303038152906040529a50505b83600101935050505061091a565b50600080896001600160a01b03168989604051610aa39190611d13565b60006040518083038185875af1925050503d8060008114610ae0576040519150601f19603f3d011682016040523d82523d6000602084013e610ae5565b606091505b509150915081610afb57610afb8a8a8a8461111c565b8b6001019b5050505050505050505050506107da565b50505050565b600083815b81811015610d4e5736878783818110610b3757610b37611ab1565b6040029190910191506000905080610b5260208401846115b8565b91505060208201356001600160a01b038216610c3f5747955080861015610ba557604051636a67a2d160e11b81526001600160a01b0383166004820152602481018290526044810187905260640161039d565b86861115610c3a57610bb78787611cbd565b95506000886001600160a01b03168760405160006040518083038185875af1925050503d8060008114610c06576040519150601f19603f3d011682016040523d82523d6000602084013e610c0b565b606091505b5050905080610c385760405163464e254d60e01b81526001600160a01b038a16600482015260240161039d565b505b610cfd565b6040516370a0823160e01b81523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa158015610c83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca79190611c7b565b955080861015610ce357604051636a67a2d160e11b81526001600160a01b0383166004820152602481018290526044810187905260640161039d565b8515610cfd57610cfd6001600160a01b038316898861114c565b816001600160a01b03167feaf449319c042c9ba3474fa0c5329eb58cd1f23be110cdbf9d697b8d303dac1587604051610d3891815260200190565b60405180910390a2836001019350505050610b1c565b50505050505050565b6000803681610d6960208601866115b8565b6020860135610d7b6040880188611c11565b929650909450925090506001600160a01b03841615610f4d577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b03161480610e0557507f00000000000000000000000064d44293eadeac464684b06bbc2e1f71042ea9866001600160a01b0316846001600160a01b0316145b15610e2e57604051631e055a2960e21b81526001600160a01b038516600482015260240161039d565b82471015610e5857604051633a6465f360e11b81524760048201526024810184905260440161039d565b600080856001600160a01b0316858585604051610e76929190611d25565b60006040518083038185875af1925050503d8060008114610eb3576040519150601f19603f3d011682016040523d82523d6000602084013e610eb8565b606091505b509150915081610f0557610f05868686868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525087925061111c915050565b856001600160a01b03167f6c936258f37a22c831493e49cb45429bdf7b6bb0e261f271a15f084e5b08aaff868686604051610f4293929190611d35565b60405180910390a250505b5050505050565b600054600160a01b900460ff1661034b57604051638dfc202b60e01b815260040160405180910390fd5b604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015282919085169063dd62ed3e90604401602060405180830381865afa158015610fcd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ff19190611c7b565b10156104d2576104d26001600160a01b038416836000196111ab565b60608161101b81601f611caa565b101561105a5760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b604482015260640161039d565b6110648284611caa565b845110156110a85760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b604482015260640161039d565b6060821580156110c75760405191506000825260208201604052611111565b6040519150601f8416801560200281840101858101878315602002848b0101015b818310156111005780518352602092830192016110e8565b5050858452601f01601f1916604052505b5090505b9392505050565b80516000036111445783838360405163e1eec8f160e01b815260040161039d93929190611d4f565b805181602001fd5b6040516001600160a01b038381166024830152604482018390526104d291859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050611237565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b1790526111fc848261129a565b610b11576040516001600160a01b0384811660248301526000604483015261123191869182169063095ea7b390606401611179565b610b1184825b600061124c6001600160a01b03841683611342565b9050805160001415801561127157508080602001905181019061126f9190611d76565b155b156104d257604051635274afe760e01b81526001600160a01b038416600482015260240161039d565b6000806000846001600160a01b0316846040516112b79190611d13565b6000604051808303816000865af19150503d80600081146112f4576040519150601f19603f3d011682016040523d82523d6000602084013e6112f9565b606091505b50915091508180156113235750805115806113235750808060200190518101906113239190611d76565b801561133957506000856001600160a01b03163b115b95945050505050565b60606111158383600084600080856001600160a01b031684866040516113689190611d13565b60006040518083038185875af1925050503d80600081146113a5576040519150601f19603f3d011682016040523d82523d6000602084013e6113aa565b606091505b50915091506113ba8683836113c4565b9695505050505050565b6060826113d9576113d482611420565b611115565b81511580156113f057506001600160a01b0384163b155b1561141957604051639996b31560e01b81526001600160a01b038516600482015260240161039d565b5080611115565b8051156114305780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b600060a0828403121561145b57600080fd5b50919050565b60008083601f84011261147357600080fd5b50813567ffffffffffffffff81111561148b57600080fd5b6020830191508360208260051b85010111156114a657600080fd5b9250929050565b600080600080600080608087890312156114c657600080fd5b863567ffffffffffffffff808211156114de57600080fd5b908801906060828b0312156114f257600080fd5b9096506020880135908082111561150857600080fd5b6115148a838b01611449565b9650604089013591508082111561152a57600080fd5b818901915089601f83011261153e57600080fd5b81358181111561154d57600080fd5b8a602082850101111561155f57600080fd5b60208301965080955050606089013591508082111561157d57600080fd5b5061158a89828a01611461565b979a9699509497509295939492505050565b80356001600160a01b03811681146115b357600080fd5b919050565b6000602082840312156115ca57600080fd5b6111158261159c565b6000806000604084860312156115e857600080fd5b833567ffffffffffffffff8082111561160057600080fd5b61160c87838801611449565b9450602086013591508082111561162257600080fd5b5061162f86828701611461565b9497909650939450505050565b6000808335601e1984360301811261165357600080fd5b83018035915067ffffffffffffffff82111561166e57600080fd5b6020019150600681901b36038213156114a657600080fd5b6000808335601e1984360301811261169d57600080fd5b830160208101925035905067ffffffffffffffff8111156116bd57600080fd5b8060061b36038213156114a657600080fd5b6001600160a01b036116e08261159c565b168252602090810135910152565b81835260208301925060008160005b848110156117225761170f86836116cf565b60409586019591909101906001016116fd565b5093949350505050565b60008235605e1983360301811261174257600080fd5b90910192915050565b6000808335601e1984360301811261176257600080fd5b830160208101925035905067ffffffffffffffff81111561178257600080fd5b8036038213156114a657600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6001600160a01b036117cb8261159c565b1682526020810135602083015260006117e7604083018361174b565b60606040860152611339606086018284611791565b6000604084835280602084015260e083016118178586611686565b60a086850152918290529060009061010086015b8183101561184f5761183d81856116cf565b9284019260019290920191840161182b565b61185c6020890189611686565b94509250603f1991508187820301606088015261187a8185856116ee565b9350506118898488018861172c565b93508086840301608087015250506118a181836117ba565b9150506118b06060850161159c565b6001600160a01b031660a08401526118ca6080850161159c565b6001600160a01b03811660c0850152611111565b600081518084526020808501945080840160005b8381101561192257815180516001600160a01b0316885283015183880152604090960195908201906001016118f2565b509495945050505050565b60005b83811015611948578181015183820152602001611930565b50506000910152565b6000815180845261196981602086016020860161192d565b601f01601f19169290920160200192915050565b60c08152600061012082016119928a8b611686565b606060c0860152918290529060009061014085015b818310156119cc576119b981856116cf565b60409384019360019390930192016119a7565b60208d013560e087015260408d013561010087015285810360208701526119f3818d6118de565b9350505050611a0d60408401896001600160a01b03169052565b8660608401528281036080840152611a258187611951565b905082810360a0840152611a3a818587611791565b9a9950505050505050505050565b6001600160a01b03841681526040602082018190528181018390526000908460608401835b86811015611a8f57611a7f82846116cf565b9183019190830190600101611a6d565b50979650505050505050565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b60008235605e19833603018112611add57600080fd5b9190910192915050565b6001600160a01b03611af88261159c565b168252602081013560208301526000611b14604083018361174b565b808260408701376000604082870101526040601f19601f8301168601019250505092915050565b6000611b478384611686565b8360005b82811015611b7057611b5d82856116cf565b6040938401939190910190600101611b4b565b50611b7e6020870187611686565b935091506000905b83821015611bab57611b9881846116cf565b6040928301926001929092019101611b86565b611bf0611be4611bc783611bc260408c018c61172c565b611ae7565b611bd360608b0161159c565b6001600160a01b0316815260200190565b611bd360808a0161159c565b979650505050505050565b60008235607e19833603018112611add57600080fd5b6000808335601e19843603018112611c2857600080fd5b83018035915067ffffffffffffffff821115611c4357600080fd5b6020019150368190038213156114a657600080fd5b600060208284031215611c6a57600080fd5b81358060030b811461111557600080fd5b600060208284031215611c8d57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561060057610600611c94565b8181038181111561060057610600611c94565b60008451611ce281846020890161192d565b845190830190611cf681836020890161192d565b8451910190611d0981836020880161192d565b0195945050505050565b60008251611add81846020870161192d565b8183823760009101908152919050565b838152604060208201526000611339604083018486611791565b60018060a01b03841681528260208201526060604082015260006113396060830184611951565b600060208284031215611d8857600080fd5b8151801515811461111557600080fdfe4f72646572206f72646572294f7264657228496e7075745b5d20696e707574732c4f75747075745b5d206f7574707574732c52656c61792072656c61792c6164647265737320757365722c6164647265737320726563697069656e7429496e707574286164647265737320746f6b656e2c75696e7432353620616d6f756e74294f7574707574286164647265737320746f6b656e2c75696e74323536206d696e4f7574707574416d6f756e742952656c61792861646472657373207461726765742c75696e743235362076616c75652c6279746573206461746129546f6b656e5065726d697373696f6e73286164647265737320746f6b656e2c75696e7432353620616d6f756e7429a264697066735822122064429d1084d8ed3c74ad89ca0e52812c4d2f1007936fb2b4f7b34f5d9ea532cd64736f6c63430008150033

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

0000000000000000000000000000000000000000000000000000000000000000

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

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


Block Transaction Gas Used Reward
view all blocks ##produced##

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

Validator Index Block Amount
View All Withdrawals

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

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