GLMR Price: $0.107521 (+6.20%)

Contract

0x603eF396029b5e89f9420b4192814aEC0664ADAb

Overview

GLMR Balance

Moonbeam Chain LogoMoonbeam Chain LogoMoonbeam Chain Logo0 GLMR

GLMR Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Swap With Permit...98916472025-03-05 21:26:1243 mins ago1741209972IN
Zenlink V2: Aggregation Router
4,000 GLMR0.02979831.25
Swap With Permit...98910402025-03-05 20:24:241 hr ago1741206264IN
Zenlink V2: Aggregation Router
1,900 GLMR0.23892531.25
Swap98874792025-03-05 14:22:427 hrs ago1741184562IN
Zenlink V2: Aggregation Router
0 GLMR0.1430794435
Swap98867452025-03-05 13:09:009 hrs ago1741180140IN
Zenlink V2: Aggregation Router
0 GLMR0.1511697431.26183772
Swap98867352025-03-05 13:08:009 hrs ago1741180080IN
Zenlink V2: Aggregation Router
0 GLMR0.0890731.25
Swap With Permit...98857742025-03-05 11:29:3610 hrs ago1741174176IN
Zenlink V2: Aggregation Router
3,270 GLMR0.059245531.25
Swap With Permit...98857052025-03-05 11:22:3010 hrs ago1741173750IN
Zenlink V2: Aggregation Router
5,000 GLMR0.072125531.25
Swap98856102025-03-05 11:12:2410 hrs ago1741173144IN
Zenlink V2: Aggregation Router
0 GLMR0.03059631.25
Swap98848522025-03-05 9:51:4212 hrs ago1741168302IN
Zenlink V2: Aggregation Router
0 GLMR0.5044375156.25
Swap98845972025-03-05 9:24:1812 hrs ago1741166658IN
Zenlink V2: Aggregation Router
0 GLMR0.0321256333
Swap98845902025-03-05 9:23:3612 hrs ago1741166616IN
Zenlink V2: Aggregation Router
0 GLMR0.0154549533
Swap98845292025-03-05 9:17:3012 hrs ago1741166250IN
Zenlink V2: Aggregation Router
0 GLMR0.14731231.25
Swap98834262025-03-05 7:26:0014 hrs ago1741159560IN
Zenlink V2: Aggregation Router
0 GLMR0.1142231.25
Swap98834182025-03-05 7:25:0614 hrs ago1741159506IN
Zenlink V2: Aggregation Router
0 GLMR0.172306531.25
Swap98811092025-03-05 3:31:0018 hrs ago1741145460IN
Zenlink V2: Aggregation Router
0 GLMR0.03059631.25
Swap98809402025-03-05 3:14:0018 hrs ago1741144440IN
Zenlink V2: Aggregation Router
0 GLMR0.17880431.25
Swap98806102025-03-05 2:40:3019 hrs ago1741142430IN
Zenlink V2: Aggregation Router
0 GLMR0.03059631.25
Swap98802242025-03-05 2:01:4220 hrs ago1741140102IN
Zenlink V2: Aggregation Router
0 GLMR0.03059631.25
Swap98800532025-03-05 1:44:3620 hrs ago1741139076IN
Zenlink V2: Aggregation Router
0 GLMR0.138639531.25
Swap98796902025-03-05 1:07:0021 hrs ago1741136820IN
Zenlink V2: Aggregation Router
0 GLMR0.1375531.25
Swap With Permit...98786472025-03-04 23:21:0022 hrs ago1741130460IN
Zenlink V2: Aggregation Router
2,014 GLMR0.11449131.25
Swap98776502025-03-04 21:40:3624 hrs ago1741124436IN
Zenlink V2: Aggregation Router
0 GLMR0.24021531.25
Swap98768822025-03-04 20:23:0025 hrs ago1741119780IN
Zenlink V2: Aggregation Router
0 GLMR0.26656831.25
Swap98764952025-03-04 19:43:4826 hrs ago1741117428IN
Zenlink V2: Aggregation Router
0 GLMR0.06722131.25
Swap98764352025-03-04 19:37:3026 hrs ago1741117050IN
Zenlink V2: Aggregation Router
0 GLMR0.075199250
View all transactions

Latest 25 internal transactions (View All)

Parent Transaction Hash Block From To
98916472025-03-05 21:26:1243 mins ago1741209972
Zenlink V2: Aggregation Router
4,000 GLMR
98910402025-03-05 20:24:241 hr ago1741206264
Zenlink V2: Aggregation Router
1,900 GLMR
98857742025-03-05 11:29:3610 hrs ago1741174176
Zenlink V2: Aggregation Router
3,270 GLMR
98857052025-03-05 11:22:3010 hrs ago1741173750
Zenlink V2: Aggregation Router
5,000 GLMR
98786472025-03-04 23:21:0022 hrs ago1741130460
Zenlink V2: Aggregation Router
2,014 GLMR
98739932025-03-04 15:28:3030 hrs ago1741102110
Zenlink V2: Aggregation Router
666 GLMR
98738132025-03-04 15:10:1230 hrs ago1741101012
Zenlink V2: Aggregation Router
200 GLMR
98737822025-03-04 15:07:0631 hrs ago1741100826
Zenlink V2: Aggregation Router
200 GLMR
98737722025-03-04 15:06:0631 hrs ago1741100766
Zenlink V2: Aggregation Router
200 GLMR
98737012025-03-04 14:58:4231 hrs ago1741100322
Zenlink V2: Aggregation Router
8,100 GLMR
98733682025-03-04 14:24:5431 hrs ago1741098294
Zenlink V2: Aggregation Router
2,000 GLMR
98732722025-03-04 14:15:0031 hrs ago1741097700
Zenlink V2: Aggregation Router
2,050 GLMR
98732412025-03-04 14:11:4831 hrs ago1741097508
Zenlink V2: Aggregation Router
2,300 GLMR
98732172025-03-04 14:09:2432 hrs ago1741097364
Zenlink V2: Aggregation Router
4,220 GLMR
98727032025-03-04 13:17:3632 hrs ago1741094256
Zenlink V2: Aggregation Router
490 GLMR
98725242025-03-04 12:59:3033 hrs ago1741093170
Zenlink V2: Aggregation Router
1,000 GLMR
98722482025-03-04 12:31:4233 hrs ago1741091502
Zenlink V2: Aggregation Router
44 GLMR
98722382025-03-04 12:30:4233 hrs ago1741091442
Zenlink V2: Aggregation Router
44 GLMR
98721372025-03-04 12:20:3033 hrs ago1741090830
Zenlink V2: Aggregation Router
540 GLMR
98714952025-03-04 11:13:5434 hrs ago1741086834
Zenlink V2: Aggregation Router
20 GLMR
98714562025-03-04 11:09:5434 hrs ago1741086594
Zenlink V2: Aggregation Router
1,500 GLMR
98667772025-03-04 3:13:4242 hrs ago1741058022
Zenlink V2: Aggregation Router
1,000 GLMR
98662752025-03-04 2:23:0643 hrs ago1741054986
Zenlink V2: Aggregation Router
530 GLMR
98660802025-03-04 2:03:3044 hrs ago1741053810
Zenlink V2: Aggregation Router
640 GLMR
98660612025-03-04 2:01:3644 hrs ago1741053696
Zenlink V2: Aggregation Router
30 GLMR
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
AggregationRouter

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 800 runs

Other Settings:
default evmVersion, MIT license

Contract Source Code (Solidity)

/**
 *Submitted for verification at moonbeam.moonscan.io on 2023-08-07
*/

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

abstract contract Ownable {
    address public owner;
    address public ownerCandidate;

    error InvalidCaller();
    error NotCandidate();

    /// @notice Emitted when the owner of the factory is changed
    /// @param oldOwner The owner before the owner was changed
    /// @param newOwner The owner after the owner was changed
    event OwnerChanged(address indexed oldOwner, address indexed newOwner);

    event Candidate(address indexed newOwner);

    modifier onlyOwner() {
        if (msg.sender != owner) revert InvalidCaller();
        _;
    }

    constructor() {
        owner = msg.sender;
        emit OwnerChanged(address(0), msg.sender);
    }

    function setOwnerCandidate(address _candidate) external onlyOwner {
        ownerCandidate = _candidate;
        emit Candidate(_candidate);
    }

    function candidateConfirm() external {
        if (msg.sender != ownerCandidate) revert NotCandidate();
        emit OwnerChanged(owner, ownerCandidate);
        owner = ownerCandidate;
        ownerCandidate = address(0);
    }
}

abstract contract EthReceiver {
    error EthDepositRejected();

    receive() external payable {
        _receive();
    }

    function _receive() internal virtual {
        if (msg.sender == tx.origin) revert EthDepositRejected();
    }
}

// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)

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

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

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

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

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

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

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

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

// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/utils/SafeERC20.sol)

// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)

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

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

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

// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)

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

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

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

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

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

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, defaultRevert);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with a
     * `customRevert` function as a fallback when `target` reverts.
     *
     * Requirements:
     *
     * - `customRevert` must be a reverting function.
     *
     * _Available since v5.0._
     */
    function functionCall(
        address target,
        bytes memory data,
        function() internal view customRevert
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, customRevert);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, defaultRevert);
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with a `customRevert` function as a fallback revert reason when `target` reverts.
     *
     * Requirements:
     *
     * - `customRevert` must be a reverting function.
     *
     * _Available since v5.0._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        function() internal view customRevert
    ) internal returns (bytes memory) {
        if (address(this).balance < value) {
            revert AddressInsufficientBalance(address(this));
        }
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, customRevert);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, defaultRevert);
    }

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

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, defaultRevert);
    }

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

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided `customRevert`) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v5.0._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        function() internal view customRevert
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check if target is a contract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                if (target.code.length == 0) {
                    revert AddressEmptyCode(target);
                }
            }
            return returndata;
        } else {
            _revert(returndata, customRevert);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or with a default revert error.
     *
     * _Available since v5.0._
     */
    function verifyCallResult(bool success, bytes memory returndata) internal view returns (bytes memory) {
        return verifyCallResult(success, returndata, defaultRevert);
    }

    /**
     * @dev Same as {xref-Address-verifyCallResult-bool-bytes-}[`verifyCallResult`], but with a
     * `customRevert` function as a fallback when `success` is `false`.
     *
     * Requirements:
     *
     * - `customRevert` must be a reverting function.
     *
     * _Available since v5.0._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        function() internal view customRevert
    ) internal view returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, customRevert);
        }
    }

    /**
     * @dev Default reverting function when no `customRevert` is provided in a function call.
     */
    function defaultRevert() internal pure {
        revert FailedInnerCall();
    }

    function _revert(bytes memory returndata, function() internal view customRevert) private view {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            customRevert();
            revert FailedInnerCall();
        }
    }
}

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

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

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

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

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

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

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

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

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

    /**
     * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
     * Revert on invalid signature.
     */
    function safePermit(
        IERC20Permit token,
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        uint256 nonceBefore = token.nonces(owner);
        token.permit(owner, spender, value, deadline, v, r, s);
        uint256 nonceAfter = token.nonces(owner);
        if (nonceAfter != nonceBefore + 1) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

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

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

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

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

/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract ERC20 {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event Transfer(address indexed from, address indexed to, uint256 amount);

    event Approval(address indexed owner, address indexed spender, uint256 amount);

    /*//////////////////////////////////////////////////////////////
                            METADATA STORAGE
    //////////////////////////////////////////////////////////////*/

    string public name;

    string public symbol;

    uint8 public immutable decimals;

    /*//////////////////////////////////////////////////////////////
                              ERC20 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 public totalSupply;

    mapping(address => uint256) public balanceOf;

    mapping(address => mapping(address => uint256)) public allowance;

    /*//////////////////////////////////////////////////////////////
                            EIP-2612 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 internal immutable INITIAL_CHAIN_ID;

    bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;

    mapping(address => uint256) public nonces;

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(
        string memory _name,
        string memory _symbol,
        uint8 _decimals
    ) {
        name = _name;
        symbol = _symbol;
        decimals = _decimals;

        INITIAL_CHAIN_ID = block.chainid;
        INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
    }

    /*//////////////////////////////////////////////////////////////
                               ERC20 LOGIC
    //////////////////////////////////////////////////////////////*/

    function approve(address spender, uint256 amount) public virtual returns (bool) {
        allowance[msg.sender][spender] = amount;

        emit Approval(msg.sender, spender, amount);

        return true;
    }

    function transfer(address to, uint256 amount) public virtual returns (bool) {
        balanceOf[msg.sender] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(msg.sender, to, amount);

        return true;
    }

    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual returns (bool) {
        uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.

        if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;

        balanceOf[from] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(from, to, amount);

        return true;
    }

    /*//////////////////////////////////////////////////////////////
                             EIP-2612 LOGIC
    //////////////////////////////////////////////////////////////*/

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public virtual {
        require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");

        // Unchecked because the only math done is incrementing
        // the owner's nonce which cannot realistically overflow.
        unchecked {
            address recoveredAddress = ecrecover(
                keccak256(
                    abi.encodePacked(
                        "\x19\x01",
                        DOMAIN_SEPARATOR(),
                        keccak256(
                            abi.encode(
                                keccak256(
                                    "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
                                ),
                                owner,
                                spender,
                                value,
                                nonces[owner]++,
                                deadline
                            )
                        )
                    )
                ),
                v,
                r,
                s
            );

            require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");

            allowance[recoveredAddress][spender] = value;
        }

        emit Approval(owner, spender, value);
    }

    function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
        return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
    }

    function computeDomainSeparator() internal view virtual returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
                    keccak256(bytes(name)),
                    keccak256("1"),
                    block.chainid,
                    address(this)
                )
            );
    }

    /*//////////////////////////////////////////////////////////////
                        INTERNAL MINT/BURN LOGIC
    //////////////////////////////////////////////////////////////*/

    function _mint(address to, uint256 amount) internal virtual {
        totalSupply += amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(address(0), to, amount);
    }

    function _burn(address from, uint256 amount) internal virtual {
        balanceOf[from] -= amount;

        // Cannot underflow because a user's balance
        // will never be larger than the total supply.
        unchecked {
            totalSupply -= amount;
        }

        emit Transfer(from, address(0), amount);
    }
}

/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer.
/// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller.
library SafeTransferLib {
    /*//////////////////////////////////////////////////////////////
                             ETH OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function safeTransferETH(address to, uint256 amount) internal {
        bool success;

        /// @solidity memory-safe-assembly
        assembly {
            // Transfer the ETH and store if it succeeded or not.
            success := call(gas(), to, amount, 0, 0, 0, 0)
        }

        require(success, "ETH_TRANSFER_FAILED");
    }

    /*//////////////////////////////////////////////////////////////
                            ERC20 OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function safeTransferFrom(
        ERC20 token,
        address from,
        address to,
        uint256 amount
    ) internal {
        bool success;

        /// @solidity memory-safe-assembly
        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "from" argument.
            mstore(add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
            mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)
            )
        }

        require(success, "TRANSFER_FROM_FAILED");
    }

    function safeTransfer(
        ERC20 token,
        address to,
        uint256 amount
    ) internal {
        bool success;

        /// @solidity memory-safe-assembly
        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
            mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
            )
        }

        require(success, "TRANSFER_FAILED");
    }

    function safeApprove(
        ERC20 token,
        address to,
        uint256 amount
    ) internal {
        bool success;

        /// @solidity memory-safe-assembly
        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
            mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
            )
        }

        require(success, "APPROVE_FAILED");
    }
}

library Constants {
    /// @dev Used as a flag for identifying the transfer of ETH instead of a token
    address internal constant NATIVE_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
    /// @dev Used as a impossible pool address
    address internal constant IMPOSSIBLE_POOL_ADDRESS = 0x0000000000000000000000000000000000000001;
    /// @dev The minimum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MIN_TICK)
    uint160 internal constant MIN_SQRT_RATIO = 4295128739;
    /// @dev The maximum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK)
    uint160 internal constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342;
}

type Currency is address;

/// @title CurrencyLibrary
/// @dev This library allows for transferring and holding native tokens and ERC20 tokens
library CurrencyLibrary {
    using CurrencyLibrary for Currency;
    using SafeERC20 for IERC20;
    using SafeTransferLib for address;

    /// @notice Thrown when a native transfer fails
    error NativeTransferFailed();

    /// @notice Thrown when an ERC20 transfer fails
    error ERC20TransferFailed();

    /// @notice Thrown when an ERC20 approve fails
    error ERC20ApproveFailed();

    Currency public constant NATIVE = Currency.wrap(Constants.NATIVE_ADDRESS);

    function transfer(Currency currency, address to, uint256 amount) internal {
        if (currency.isNative()) {
            to.safeTransferETH(amount);
        } else {
            IERC20(Currency.unwrap(currency)).safeTransfer(to, amount);
        }
    }

    function transferFrom(Currency currency, address from, address to, uint256 amount) internal {
        if (currency.isNative()) {
            revert NativeTransferFailed();
        } else {
            IERC20(Currency.unwrap(currency)).safeTransferFrom(from, to, amount);
        }
    }

    function approve(Currency currency, address to, uint256 amount) internal {
        if (currency.isNative()) {
            revert ERC20ApproveFailed();
        } else {
            IERC20(Currency.unwrap(currency)).safeIncreaseAllowance(to, amount);
        }
    }

    function balanceOfSelf(Currency currency) internal view returns (uint256) {
        return balanceOf(currency, address(this));
    }

    function balanceOf(Currency currency, address owner) internal view returns (uint256) {
        if (currency.isNative()) {
            return owner.balance;
        } else {
            return IERC20(Currency.unwrap(currency)).balanceOf(owner);
        }
    }

    function equals(Currency currency, Currency other) internal pure returns (bool) {
        return Currency.unwrap(currency) == Currency.unwrap(other);
    }

    function isNative(Currency currency) internal pure returns (bool) {
        return Currency.unwrap(currency) == Currency.unwrap(NATIVE);
    }
}

interface IAggregationRouter {
    struct SwapDescription {
        Currency srcToken;
        Currency dstToken;
        address dstReceiver;
        uint256 amount;
        uint256 minReturnAmount;
    }

    function swap(
        IAggregationExecutor executor,
        SwapDescription memory desc,
        bytes memory route
    ) external payable returns (uint256 returnAmount, uint256 spentAmount);
}

interface IAggregationExecutor {
    function excute(
        address msgSender,
        IAggregationRouter.SwapDescription memory desc,
        bytes memory route
    ) external payable;
}

/// @notice Gas optimized reentrancy protection for smart contracts.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/ReentrancyGuard.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/security/ReentrancyGuard.sol)
abstract contract ReentrancyGuard {
    uint256 private locked = 1;

    modifier nonReentrant() virtual {
        require(locked == 1, "REENTRANCY");

        locked = 2;

        _;

        locked = 1;
    }
}

interface IEIP712 {
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

/// @title AllowanceTransfer
/// @notice Handles ERC20 token permissions through signature based allowance setting and ERC20 token transfers by checking allowed amounts
/// @dev Requires user's token approval on the Permit2 contract
interface IAllowanceTransfer is IEIP712 {
    /// @notice Thrown when an allowance on a token has expired.
    /// @param deadline The timestamp at which the allowed amount is no longer valid
    error AllowanceExpired(uint256 deadline);

    /// @notice Thrown when an allowance on a token has been depleted.
    /// @param amount The maximum amount allowed
    error InsufficientAllowance(uint256 amount);

    /// @notice Thrown when too many nonces are invalidated.
    error ExcessiveInvalidation();

    /// @notice Emits an event when the owner successfully invalidates an ordered nonce.
    event NonceInvalidation(
        address indexed owner, address indexed token, address indexed spender, uint48 newNonce, uint48 oldNonce
    );

    /// @notice Emits an event when the owner successfully sets permissions on a token for the spender.
    event Approval(
        address indexed owner, address indexed token, address indexed spender, uint160 amount, uint48 expiration
    );

    /// @notice Emits an event when the owner successfully sets permissions using a permit signature on a token for the spender.
    event Permit(
        address indexed owner,
        address indexed token,
        address indexed spender,
        uint160 amount,
        uint48 expiration,
        uint48 nonce
    );

    /// @notice Emits an event when the owner sets the allowance back to 0 with the lockdown function.
    event Lockdown(address indexed owner, address token, address spender);

    /// @notice The permit data for a token
    struct PermitDetails {
        // ERC20 token address
        address token;
        // the maximum amount allowed to spend
        uint160 amount;
        // timestamp at which a spender's token allowances become invalid
        uint48 expiration;
        // an incrementing value indexed per owner,token,and spender for each signature
        uint48 nonce;
    }

    /// @notice The permit message signed for a single token allownce
    struct PermitSingle {
        // the permit data for a single token alownce
        PermitDetails details;
        // address permissioned on the allowed tokens
        address spender;
        // deadline on the permit signature
        uint256 sigDeadline;
    }

    /// @notice The permit message signed for multiple token allowances
    struct PermitBatch {
        // the permit data for multiple token allowances
        PermitDetails[] details;
        // address permissioned on the allowed tokens
        address spender;
        // deadline on the permit signature
        uint256 sigDeadline;
    }

    /// @notice The saved permissions
    /// @dev This info is saved per owner, per token, per spender and all signed over in the permit message
    /// @dev Setting amount to type(uint160).max sets an unlimited approval
    struct PackedAllowance {
        // amount allowed
        uint160 amount;
        // permission expiry
        uint48 expiration;
        // an incrementing value indexed per owner,token,and spender for each signature
        uint48 nonce;
    }

    /// @notice A token spender pair.
    struct TokenSpenderPair {
        // the token the spender is approved
        address token;
        // the spender address
        address spender;
    }

    /// @notice Details for a token transfer.
    struct AllowanceTransferDetails {
        // the owner of the token
        address from;
        // the recipient of the token
        address to;
        // the amount of the token
        uint160 amount;
        // the token to be transferred
        address token;
    }

    /// @notice A mapping from owner address to token address to spender address to PackedAllowance struct, which contains details and conditions of the approval.
    /// @notice The mapping is indexed in the above order see: allowance[ownerAddress][tokenAddress][spenderAddress]
    /// @dev The packed slot holds the allowed amount, expiration at which the allowed amount is no longer valid, and current nonce thats updated on any signature based approvals.
    function allowance(address user, address token, address spender)
        external
        view
        returns (uint160 amount, uint48 expiration, uint48 nonce);

    /// @notice Approves the spender to use up to amount of the specified token up until the expiration
    /// @param token The token to approve
    /// @param spender The spender address to approve
    /// @param amount The approved amount of the token
    /// @param expiration The timestamp at which the approval is no longer valid
    /// @dev The packed allowance also holds a nonce, which will stay unchanged in approve
    /// @dev Setting amount to type(uint160).max sets an unlimited approval
    function approve(address token, address spender, uint160 amount, uint48 expiration) external;

    /// @notice Permit a spender to a given amount of the owners token via the owner's EIP-712 signature
    /// @dev May fail if the owner's nonce was invalidated in-flight by invalidateNonce
    /// @param owner The owner of the tokens being approved
    /// @param permitSingle Data signed over by the owner specifying the terms of approval
    /// @param signature The owner's signature over the permit data
    function permit(address owner, PermitSingle memory permitSingle, bytes calldata signature) external;

    /// @notice Permit a spender to the signed amounts of the owners tokens via the owner's EIP-712 signature
    /// @dev May fail if the owner's nonce was invalidated in-flight by invalidateNonce
    /// @param owner The owner of the tokens being approved
    /// @param permitBatch Data signed over by the owner specifying the terms of approval
    /// @param signature The owner's signature over the permit data
    function permit(address owner, PermitBatch memory permitBatch, bytes calldata signature) external;

    /// @notice Transfer approved tokens from one address to another
    /// @param from The address to transfer from
    /// @param to The address of the recipient
    /// @param amount The amount of the token to transfer
    /// @param token The token address to transfer
    /// @dev Requires the from address to have approved at least the desired amount
    /// of tokens to msg.sender.
    function transferFrom(address from, address to, uint160 amount, address token) external;

    /// @notice Transfer approved tokens in a batch
    /// @param transferDetails Array of owners, recipients, amounts, and tokens for the transfers
    /// @dev Requires the from addresses to have approved at least the desired amount
    /// of tokens to msg.sender.
    function transferFrom(AllowanceTransferDetails[] calldata transferDetails) external;

    /// @notice Enables performing a "lockdown" of the sender's Permit2 identity
    /// by batch revoking approvals
    /// @param approvals Array of approvals to revoke.
    function lockdown(TokenSpenderPair[] calldata approvals) external;

    /// @notice Invalidate nonces for a given (token, spender) pair
    /// @param token The token to invalidate nonces for
    /// @param spender The spender to invalidate nonces for
    /// @param newNonce The new nonce to set. Invalidates all nonces less than it.
    /// @dev Can't invalidate more than 2**16 nonces per transaction.
    function invalidateNonces(address token, address spender, uint48 newNonce) external;
}

contract AggregationRouter is IAggregationRouter, Ownable, EthReceiver, ReentrancyGuard {
    using CurrencyLibrary for Currency;

    IAllowanceTransfer public permit2;

    error ZeroMinReturnAmount();
    error EmptyRouteData();
    error InvalidMsgValue();
    error MinimalOutputBalanceViolation();
    error EmptyPermit2Address();
    error InvalidSpender();

    event Swap(
        address sender,
        Currency srcToken,
        Currency dstToken,
        address dstReceiver,
        uint256 amount,
        uint256 returnAmount
    );

    /**
     * @notice Retrieves funds accidently sent directly to the contract address
     * @param currency currency to retrieve
     * @param amount amount to retrieve
     */
    function rescueFunds(Currency currency, uint256 amount) external onlyOwner {
        currency.transfer(msg.sender, amount);
    }

    function setPermit2(IAllowanceTransfer _permit2) external onlyOwner {
        permit2 = _permit2;
    }

    function swap(
        IAggregationExecutor executor,
        SwapDescription memory desc,
        bytes memory route
    ) external payable nonReentrant returns (uint256 returnAmount, uint256 spentAmount) {
        _checkParams(desc, route);
        bool srcNative = desc.srcToken.isNative();
        if (!srcNative) {
            desc.srcToken.transferFrom(msg.sender, address(executor), desc.amount);
        }
        (returnAmount, spentAmount) = _swap(executor, desc, route);
    }

    function swapWithPermit2(
        IAggregationExecutor executor,
        SwapDescription memory desc,
        bytes memory route
    ) external payable nonReentrant returns (uint256 returnAmount, uint256 spentAmount) {
        _checkParams(desc, route);
        bool srcNative = desc.srcToken.isNative();
        if (!srcNative) {
            if (address(permit2) == address(0)) revert EmptyPermit2Address();
            permit2.transferFrom(
                msg.sender, 
                address(executor), 
                uint160(desc.amount), 
                Currency.unwrap(desc.srcToken)
            );
        }
        (returnAmount, spentAmount) = _swap(executor, desc, route);
    }

    function swapWithPermit2Signature(
        IAggregationExecutor executor,
        SwapDescription memory desc,
        bytes memory route,
        IAllowanceTransfer.PermitSingle calldata permitSingle, 
        bytes calldata signature
    ) external payable nonReentrant returns (uint256 returnAmount, uint256 spentAmount) {
        _checkParams(desc, route);
        bool srcNative = desc.srcToken.isNative();
        if (!srcNative) {
            if (address(permit2) == address(0)) revert EmptyPermit2Address();
            if (permitSingle.spender != address(this)) revert InvalidSpender();
            permit2.permit(msg.sender, permitSingle, signature);
            permit2.transferFrom(
                msg.sender, 
                address(executor), 
                uint160(desc.amount), 
                Currency.unwrap(desc.srcToken)
            );
        }
        (returnAmount, spentAmount) = _swap(executor, desc, route);
    }

    function _checkParams(SwapDescription memory desc, bytes memory route) internal {
        if (desc.minReturnAmount == 0) revert ZeroMinReturnAmount();
        if (route.length == 0) revert EmptyRouteData();
        bool srcNative = desc.srcToken.isNative();
        if (srcNative && msg.value < desc.amount) revert InvalidMsgValue();
    }

    function _swap(
        IAggregationExecutor executor,
        SwapDescription memory desc,
        bytes memory route
    ) internal returns (uint256 returnAmount, uint256 spentAmount) {
        Currency dstToken = desc.dstToken;
        address dstReceiver = desc.dstReceiver == address(0) ? msg.sender : desc.dstReceiver;
        uint256 dstBalanceInitial = dstToken.balanceOf(dstReceiver);

        bytes memory callData = abi.encodeCall(executor.excute, (msg.sender, desc, route));
        (bool success, bytes memory returnData) = address(executor).call{value: msg.value}(callData);
        if (!success) {
            assembly {
                revert(add(returnData, 32), mload(returnData))
            }
        }

        spentAmount = desc.amount;
        uint256 dstBalanceFinal = dstToken.balanceOf(dstReceiver);
        returnAmount = dstBalanceFinal - dstBalanceInitial;

        if (returnAmount < desc.minReturnAmount) revert MinimalOutputBalanceViolation();

        emit Swap(msg.sender, desc.srcToken, desc.dstToken, dstReceiver, desc.amount, returnAmount);
    }
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"EmptyPermit2Address","type":"error"},{"inputs":[],"name":"EmptyRouteData","type":"error"},{"inputs":[],"name":"EthDepositRejected","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"InvalidCaller","type":"error"},{"inputs":[],"name":"InvalidMsgValue","type":"error"},{"inputs":[],"name":"InvalidSpender","type":"error"},{"inputs":[],"name":"MinimalOutputBalanceViolation","type":"error"},{"inputs":[],"name":"NativeTransferFailed","type":"error"},{"inputs":[],"name":"NotCandidate","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"ZeroMinReturnAmount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"Candidate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"Currency","name":"srcToken","type":"address"},{"indexed":false,"internalType":"Currency","name":"dstToken","type":"address"},{"indexed":false,"internalType":"address","name":"dstReceiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"returnAmount","type":"uint256"}],"name":"Swap","type":"event"},{"inputs":[],"name":"candidateConfirm","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ownerCandidate","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"permit2","outputs":[{"internalType":"contract IAllowanceTransfer","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"Currency","name":"currency","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"rescueFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_candidate","type":"address"}],"name":"setOwnerCandidate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IAllowanceTransfer","name":"_permit2","type":"address"}],"name":"setPermit2","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IAggregationExecutor","name":"executor","type":"address"},{"components":[{"internalType":"Currency","name":"srcToken","type":"address"},{"internalType":"Currency","name":"dstToken","type":"address"},{"internalType":"address","name":"dstReceiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minReturnAmount","type":"uint256"}],"internalType":"struct IAggregationRouter.SwapDescription","name":"desc","type":"tuple"},{"internalType":"bytes","name":"route","type":"bytes"}],"name":"swap","outputs":[{"internalType":"uint256","name":"returnAmount","type":"uint256"},{"internalType":"uint256","name":"spentAmount","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IAggregationExecutor","name":"executor","type":"address"},{"components":[{"internalType":"Currency","name":"srcToken","type":"address"},{"internalType":"Currency","name":"dstToken","type":"address"},{"internalType":"address","name":"dstReceiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minReturnAmount","type":"uint256"}],"internalType":"struct IAggregationRouter.SwapDescription","name":"desc","type":"tuple"},{"internalType":"bytes","name":"route","type":"bytes"}],"name":"swapWithPermit2","outputs":[{"internalType":"uint256","name":"returnAmount","type":"uint256"},{"internalType":"uint256","name":"spentAmount","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IAggregationExecutor","name":"executor","type":"address"},{"components":[{"internalType":"Currency","name":"srcToken","type":"address"},{"internalType":"Currency","name":"dstToken","type":"address"},{"internalType":"address","name":"dstReceiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minReturnAmount","type":"uint256"}],"internalType":"struct IAggregationRouter.SwapDescription","name":"desc","type":"tuple"},{"internalType":"bytes","name":"route","type":"bytes"},{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint160","name":"amount","type":"uint160"},{"internalType":"uint48","name":"expiration","type":"uint48"},{"internalType":"uint48","name":"nonce","type":"uint48"}],"internalType":"struct IAllowanceTransfer.PermitDetails","name":"details","type":"tuple"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"sigDeadline","type":"uint256"}],"internalType":"struct IAllowanceTransfer.PermitSingle","name":"permitSingle","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"swapWithPermit2Signature","outputs":[{"internalType":"uint256","name":"returnAmount","type":"uint256"},{"internalType":"uint256","name":"spentAmount","type":"uint256"}],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]

6080604052600160025534801561001557600080fd5b50600080546001600160a01b0319163390811782556040519091907fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c908290a3611320806100646000396000f3fe6080604052600436106100b55760003560e01c80635f504a82116100695780638da5cb5b1161004e5780638da5cb5b146101b65780639a2f2dfa146101d6578063a036c7b1146101f657600080fd5b80635f504a821461017657806378e3214f1461019657600080fd5b80633cf807871161009a5780633cf80787146101265780633f0232301461014e57806342a568cf1461016357600080fd5b8063101ec30a146100c957806312261ee7146100e957600080fd5b366100c4576100c2610209565b005b600080fd5b3480156100d557600080fd5b506100c26100e4366004610e25565b61022b565b3480156100f557600080fd5b50600354610109906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b610139610134366004610f77565b610285565b6040805192835260208301919091520161011d565b34801561015a57600080fd5b506100c26103c2565b610139610171366004610fd8565b61045e565b34801561018257600080fd5b50600154610109906001600160a01b031681565b3480156101a257600080fd5b506100c26101b13660046110b2565b610639565b3480156101c257600080fd5b50600054610109906001600160a01b031681565b3480156101e257600080fd5b506100c26101f1366004610e25565b61067c565b610139610204366004610f77565b6106fe565b32330361022957604051631b10b0f960e01b815260040160405180910390fd5b565b6000546001600160a01b03163314610256576040516348f5c3ed60e01b815260040160405180910390fd5b6003805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b6000806002546001146102cc5760405162461bcd60e51b815260206004820152600a6024820152695245454e5452414e435960b01b60448201526064015b60405180910390fd5b600280556102da8484610794565b83516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14806103a5576003546001600160a01b03166103295760405163022369ab60e51b815260040160405180910390fd5b60035460608601518651604051631b63c28b60e11b81523360048201526001600160a01b038a81166024830152928316604482015290821660648201529116906336c7851690608401600060405180830381600087803b15801561038c57600080fd5b505af11580156103a0573d6000803e3d6000fd5b505050505b6103b086868661082f565b60016002559097909650945050505050565b6001546001600160a01b031633146103ed57604051634f32a51b60e01b815260040160405180910390fd5b600154600080546040516001600160a01b0393841693909116917fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c91a3600180546000805473ffffffffffffffffffffffffffffffffffffffff199081166001600160a01b03841617909155169055565b6000806002546001146104a05760405162461bcd60e51b815260206004820152600a6024820152695245454e5452414e435960b01b60448201526064016102c3565b600280556104ae8787610794565b86516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1480610619576003546001600160a01b03166104fd5760405163022369ab60e51b815260040160405180910390fd5b3061050e60a0880160808901610e25565b6001600160a01b03161461053557604051635461585f60e01b815260040160405180910390fd5b6003546040516302b67b5760e41b81526001600160a01b0390911690632b67b5709061056b9033908a908a908a90600401611122565b600060405180830381600087803b15801561058557600080fd5b505af1158015610599573d6000803e3d6000fd5b505060035460608b01518b51604051631b63c28b60e11b81523360048201526001600160a01b038f8116602483015292831660448201529082166064820152911692506336c785169150608401600060405180830381600087803b15801561060057600080fd5b505af1158015610614573d6000803e3d6000fd5b505050505b61062489898961082f565b6001600255909a909950975050505050505050565b6000546001600160a01b03163314610664576040516348f5c3ed60e01b815260040160405180910390fd5b6106786001600160a01b0383163383610a1b565b5050565b6000546001600160a01b031633146106a7576040516348f5c3ed60e01b815260040160405180910390fd5b6001805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081179091556040517f8cc40b9abca4a505a92028908f9d913d621d18112c69412806506f02333f26b490600090a250565b6000806002546001146107405760405162461bcd60e51b815260206004820152600a6024820152695245454e5452414e435960b01b60448201526064016102c3565b6002805561074e8484610794565b83516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14806103a557606085015185516103a5916001600160a01b039091169033908990610a66565b81608001516000036107b95760405163c74165e360e01b815260040160405180910390fd5b80516000036107db5760405163d2fab0b160e01b815260040160405180910390fd5b81516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1480801561080c5750826060015134105b1561082a57604051631841b4e160e01b815260040160405180910390fd5b505050565b60208201516040830151600091829182906001600160a01b03161561085857856040015161085a565b335b905060006108716001600160a01b03841683610abe565b90506000886001600160a01b031663f8d09f48338a8a604051602401610899939291906111f3565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090506000808a6001600160a01b031634846040516108f99190611272565b60006040518083038185875af1925050503d8060008114610936576040519150601f19603f3d011682016040523d82523d6000602084013e61093b565b606091505b50915091508161094d57805160208201fd5b60608a0151965060006109696001600160a01b03881687610abe565b9050610975858261128e565b98508a6080015189101561099c5760405163858a872160e01b815260040160405180910390fd5b8a516020808d01516060808f0151604080513381526001600160a01b039687169581019590955292851684840152938a1690830152608082019290925260a081018b905290517f20efd6d5195b7b50273f01cd79a27989255356f9f13293edc53ee142accfdb759181900360c00190a150505050505050935093915050565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b03841603610a525761082a6001600160a01b03831682610b68565b61082a6001600160a01b0384168383610bc3565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b03851603610aa357604051633d2cec6f60e21b815260040160405180910390fd5b610ab86001600160a01b038516848484610c37565b50505050565b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b03841603610af557506001600160a01b03811631610b62565b6040516370a0823160e01b81526001600160a01b0383811660048301528416906370a0823190602401602060405180830381865afa158015610b3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b5f91906112af565b90505b92915050565b600080600080600085875af190508061082a5760405162461bcd60e51b815260206004820152601360248201527f4554485f5452414e534645525f4641494c45440000000000000000000000000060448201526064016102c3565b6040516001600160a01b0383811660248301526044820183905261082a91859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050610c70565b6040516001600160a01b038481166024830152838116604483015260648201839052610ab89186918216906323b872dd90608401610bf0565b6000610c856001600160a01b03841683610cd3565b90508051600014158015610caa575080806020019051810190610ca891906112c8565b155b1561082a57604051635274afe760e01b81526001600160a01b03841660048201526024016102c3565b6060610b5f83836000610ce4610cfd565b604051630a12f52160e11b815260040160405180910390fd5b606082471015610d225760405163cd78605960e01b81523060048201526024016102c3565b600080866001600160a01b03168587604051610d3e9190611272565b60006040518083038185875af1925050503d8060008114610d7b576040519150601f19603f3d011682016040523d82523d6000602084013e610d80565b606091505b5091509150610d9187838387610d9e565b925050505b949350505050565b60608315610dec578251600003610de557846001600160a01b03163b600003610de557604051639996b31560e01b81526001600160a01b03861660048201526024016102c3565b5081610d96565b610d968383815115610e015781518083602001fd5b610ce48163ffffffff16565b6001600160a01b0381168114610e2257600080fd5b50565b600060208284031215610e3757600080fd5b8135610e4281610e0d565b9392505050565b634e487b7160e01b600052604160045260246000fd5b600060a08284031215610e7157600080fd5b60405160a0810181811067ffffffffffffffff82111715610e9457610e94610e49565b6040529050808235610ea581610e0d565b81526020830135610eb581610e0d565b60208201526040830135610ec881610e0d565b8060408301525060608301356060820152608083013560808201525092915050565b600082601f830112610efb57600080fd5b813567ffffffffffffffff80821115610f1657610f16610e49565b604051601f8301601f19908116603f01168101908282118183101715610f3e57610f3e610e49565b81604052838152866020858801011115610f5757600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080600060e08486031215610f8c57600080fd5b8335610f9781610e0d565b9250610fa68560208601610e5f565b915060c084013567ffffffffffffffff811115610fc257600080fd5b610fce86828701610eea565b9150509250925092565b6000806000806000808688036101c0811215610ff357600080fd5b8735610ffe81610e0d565b965061100d8960208a01610e5f565b955060c088013567ffffffffffffffff8082111561102a57600080fd5b6110368b838c01610eea565b965060c060df198401121561104a57600080fd5b60e08a0195506101a08a013592508083111561106557600080fd5b828a0192508a601f84011261107957600080fd5b823591508082111561108a57600080fd5b5089602082840101111561109d57600080fd5b60208201935080925050509295509295509295565b600080604083850312156110c557600080fd5b82356110d081610e0d565b946020939093013593505050565b803565ffffffffffff811681146110f457600080fd5b919050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60006101006001600160a01b038088168452863561113f81610e0d565b818116602086015250602087013561115681610e0d565b81811660408601525061116b604088016110de565b65ffffffffffff80821660608701528061118760608b016110de565b1660808701525050608087013561119d81610e0d565b81811660a0860152505060a086013560c08401528060e08401526111c481840185876110f9565b979650505050505050565b60005b838110156111ea5781810151838201526020016111d2565b50506000910152565b60006001600160a01b0380861683528085511660208401528060208601511660408401528060408601511660608401525060608401516080830152608084015160a083015260e060c083015282518060e084015261010061125a82828601602088016111cf565b80601f19601f84011685010192505050949350505050565b600082516112848184602087016111cf565b9190910192915050565b81810381811115610b6257634e487b7160e01b600052601160045260246000fd5b6000602082840312156112c157600080fd5b5051919050565b6000602082840312156112da57600080fd5b81518015158114610e4257600080fdfea2646970667358221220f9c1febef50be336455a65e4dfce5ebff83f15768330c89ca972e718d65e80ed64736f6c63430008130033

Deployed Bytecode

0x6080604052600436106100b55760003560e01c80635f504a82116100695780638da5cb5b1161004e5780638da5cb5b146101b65780639a2f2dfa146101d6578063a036c7b1146101f657600080fd5b80635f504a821461017657806378e3214f1461019657600080fd5b80633cf807871161009a5780633cf80787146101265780633f0232301461014e57806342a568cf1461016357600080fd5b8063101ec30a146100c957806312261ee7146100e957600080fd5b366100c4576100c2610209565b005b600080fd5b3480156100d557600080fd5b506100c26100e4366004610e25565b61022b565b3480156100f557600080fd5b50600354610109906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b610139610134366004610f77565b610285565b6040805192835260208301919091520161011d565b34801561015a57600080fd5b506100c26103c2565b610139610171366004610fd8565b61045e565b34801561018257600080fd5b50600154610109906001600160a01b031681565b3480156101a257600080fd5b506100c26101b13660046110b2565b610639565b3480156101c257600080fd5b50600054610109906001600160a01b031681565b3480156101e257600080fd5b506100c26101f1366004610e25565b61067c565b610139610204366004610f77565b6106fe565b32330361022957604051631b10b0f960e01b815260040160405180910390fd5b565b6000546001600160a01b03163314610256576040516348f5c3ed60e01b815260040160405180910390fd5b6003805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b6000806002546001146102cc5760405162461bcd60e51b815260206004820152600a6024820152695245454e5452414e435960b01b60448201526064015b60405180910390fd5b600280556102da8484610794565b83516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14806103a5576003546001600160a01b03166103295760405163022369ab60e51b815260040160405180910390fd5b60035460608601518651604051631b63c28b60e11b81523360048201526001600160a01b038a81166024830152928316604482015290821660648201529116906336c7851690608401600060405180830381600087803b15801561038c57600080fd5b505af11580156103a0573d6000803e3d6000fd5b505050505b6103b086868661082f565b60016002559097909650945050505050565b6001546001600160a01b031633146103ed57604051634f32a51b60e01b815260040160405180910390fd5b600154600080546040516001600160a01b0393841693909116917fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c91a3600180546000805473ffffffffffffffffffffffffffffffffffffffff199081166001600160a01b03841617909155169055565b6000806002546001146104a05760405162461bcd60e51b815260206004820152600a6024820152695245454e5452414e435960b01b60448201526064016102c3565b600280556104ae8787610794565b86516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1480610619576003546001600160a01b03166104fd5760405163022369ab60e51b815260040160405180910390fd5b3061050e60a0880160808901610e25565b6001600160a01b03161461053557604051635461585f60e01b815260040160405180910390fd5b6003546040516302b67b5760e41b81526001600160a01b0390911690632b67b5709061056b9033908a908a908a90600401611122565b600060405180830381600087803b15801561058557600080fd5b505af1158015610599573d6000803e3d6000fd5b505060035460608b01518b51604051631b63c28b60e11b81523360048201526001600160a01b038f8116602483015292831660448201529082166064820152911692506336c785169150608401600060405180830381600087803b15801561060057600080fd5b505af1158015610614573d6000803e3d6000fd5b505050505b61062489898961082f565b6001600255909a909950975050505050505050565b6000546001600160a01b03163314610664576040516348f5c3ed60e01b815260040160405180910390fd5b6106786001600160a01b0383163383610a1b565b5050565b6000546001600160a01b031633146106a7576040516348f5c3ed60e01b815260040160405180910390fd5b6001805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081179091556040517f8cc40b9abca4a505a92028908f9d913d621d18112c69412806506f02333f26b490600090a250565b6000806002546001146107405760405162461bcd60e51b815260206004820152600a6024820152695245454e5452414e435960b01b60448201526064016102c3565b6002805561074e8484610794565b83516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14806103a557606085015185516103a5916001600160a01b039091169033908990610a66565b81608001516000036107b95760405163c74165e360e01b815260040160405180910390fd5b80516000036107db5760405163d2fab0b160e01b815260040160405180910390fd5b81516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1480801561080c5750826060015134105b1561082a57604051631841b4e160e01b815260040160405180910390fd5b505050565b60208201516040830151600091829182906001600160a01b03161561085857856040015161085a565b335b905060006108716001600160a01b03841683610abe565b90506000886001600160a01b031663f8d09f48338a8a604051602401610899939291906111f3565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090506000808a6001600160a01b031634846040516108f99190611272565b60006040518083038185875af1925050503d8060008114610936576040519150601f19603f3d011682016040523d82523d6000602084013e61093b565b606091505b50915091508161094d57805160208201fd5b60608a0151965060006109696001600160a01b03881687610abe565b9050610975858261128e565b98508a6080015189101561099c5760405163858a872160e01b815260040160405180910390fd5b8a516020808d01516060808f0151604080513381526001600160a01b039687169581019590955292851684840152938a1690830152608082019290925260a081018b905290517f20efd6d5195b7b50273f01cd79a27989255356f9f13293edc53ee142accfdb759181900360c00190a150505050505050935093915050565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b03841603610a525761082a6001600160a01b03831682610b68565b61082a6001600160a01b0384168383610bc3565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b03851603610aa357604051633d2cec6f60e21b815260040160405180910390fd5b610ab86001600160a01b038516848484610c37565b50505050565b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b03841603610af557506001600160a01b03811631610b62565b6040516370a0823160e01b81526001600160a01b0383811660048301528416906370a0823190602401602060405180830381865afa158015610b3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b5f91906112af565b90505b92915050565b600080600080600085875af190508061082a5760405162461bcd60e51b815260206004820152601360248201527f4554485f5452414e534645525f4641494c45440000000000000000000000000060448201526064016102c3565b6040516001600160a01b0383811660248301526044820183905261082a91859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050610c70565b6040516001600160a01b038481166024830152838116604483015260648201839052610ab89186918216906323b872dd90608401610bf0565b6000610c856001600160a01b03841683610cd3565b90508051600014158015610caa575080806020019051810190610ca891906112c8565b155b1561082a57604051635274afe760e01b81526001600160a01b03841660048201526024016102c3565b6060610b5f83836000610ce4610cfd565b604051630a12f52160e11b815260040160405180910390fd5b606082471015610d225760405163cd78605960e01b81523060048201526024016102c3565b600080866001600160a01b03168587604051610d3e9190611272565b60006040518083038185875af1925050503d8060008114610d7b576040519150601f19603f3d011682016040523d82523d6000602084013e610d80565b606091505b5091509150610d9187838387610d9e565b925050505b949350505050565b60608315610dec578251600003610de557846001600160a01b03163b600003610de557604051639996b31560e01b81526001600160a01b03861660048201526024016102c3565b5081610d96565b610d968383815115610e015781518083602001fd5b610ce48163ffffffff16565b6001600160a01b0381168114610e2257600080fd5b50565b600060208284031215610e3757600080fd5b8135610e4281610e0d565b9392505050565b634e487b7160e01b600052604160045260246000fd5b600060a08284031215610e7157600080fd5b60405160a0810181811067ffffffffffffffff82111715610e9457610e94610e49565b6040529050808235610ea581610e0d565b81526020830135610eb581610e0d565b60208201526040830135610ec881610e0d565b8060408301525060608301356060820152608083013560808201525092915050565b600082601f830112610efb57600080fd5b813567ffffffffffffffff80821115610f1657610f16610e49565b604051601f8301601f19908116603f01168101908282118183101715610f3e57610f3e610e49565b81604052838152866020858801011115610f5757600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080600060e08486031215610f8c57600080fd5b8335610f9781610e0d565b9250610fa68560208601610e5f565b915060c084013567ffffffffffffffff811115610fc257600080fd5b610fce86828701610eea565b9150509250925092565b6000806000806000808688036101c0811215610ff357600080fd5b8735610ffe81610e0d565b965061100d8960208a01610e5f565b955060c088013567ffffffffffffffff8082111561102a57600080fd5b6110368b838c01610eea565b965060c060df198401121561104a57600080fd5b60e08a0195506101a08a013592508083111561106557600080fd5b828a0192508a601f84011261107957600080fd5b823591508082111561108a57600080fd5b5089602082840101111561109d57600080fd5b60208201935080925050509295509295509295565b600080604083850312156110c557600080fd5b82356110d081610e0d565b946020939093013593505050565b803565ffffffffffff811681146110f457600080fd5b919050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60006101006001600160a01b038088168452863561113f81610e0d565b818116602086015250602087013561115681610e0d565b81811660408601525061116b604088016110de565b65ffffffffffff80821660608701528061118760608b016110de565b1660808701525050608087013561119d81610e0d565b81811660a0860152505060a086013560c08401528060e08401526111c481840185876110f9565b979650505050505050565b60005b838110156111ea5781810151838201526020016111d2565b50506000910152565b60006001600160a01b0380861683528085511660208401528060208601511660408401528060408601511660608401525060608401516080830152608084015160a083015260e060c083015282518060e084015261010061125a82828601602088016111cf565b80601f19601f84011685010192505050949350505050565b600082516112848184602087016111cf565b9190910192915050565b81810381811115610b6257634e487b7160e01b600052601160045260246000fd5b6000602082840312156112c157600080fd5b5051919050565b6000602082840312156112da57600080fd5b81518015158114610e4257600080fdfea2646970667358221220f9c1febef50be336455a65e4dfce5ebff83f15768330c89ca972e718d65e80ed64736f6c63430008130033

Deployed Bytecode Sourcemap

47506:4670:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1263:10;:8;:10::i;:::-;47506:4670;;;;;48405:105;;;;;;;;;;-1:-1:-1;48405:105:0;;;;;:::i;:::-;;:::i;47644:33::-;;;;;;;;;;-1:-1:-1;47644:33:0;;;;-1:-1:-1;;;;;47644:33:0;;;;;;-1:-1:-1;;;;;683:55:1;;;665:74;;653:2;638:18;47644:33:0;;;;;;;;49024:709;;;;;;:::i;:::-;;:::i;:::-;;;;3385:25:1;;;3441:2;3426:18;;3419:34;;;;3358:18;49024:709:0;3211:248:1;913:233:0;;;;;;;;;;;;;:::i;49741:965::-;;;;;;:::i;:::-;;:::i;121:29::-;;;;;;;;;;-1:-1:-1;121:29:0;;;;-1:-1:-1;;;;;121:29:0;;;48266:131;;;;;;;;;;-1:-1:-1;48266:131:0;;;;;:::i;:::-;;:::i;94:20::-;;;;;;;;;;-1:-1:-1;94:20:0;;;;-1:-1:-1;;;;;94:20:0;;;756:149;;;;;;;;;;-1:-1:-1;756:149:0;;;;;:::i;:::-;;:::i;48518:498::-;;;;;;:::i;:::-;;:::i;1289:112::-;1355:9;1341:10;:23;1337:56;;1373:20;;-1:-1:-1;;;1373:20:0;;;;;;;;;;;1337:56;1289:112::o;48405:105::-;588:5;;-1:-1:-1;;;;;588:5:0;574:10;:19;570:47;;602:15;;-1:-1:-1;;;602:15:0;;;;;;;;;;;570:47;48484:7:::1;:18:::0;;-1:-1:-1;;48484:18:0::1;-1:-1:-1::0;;;;;48484:18:0;;;::::1;::::0;;;::::1;::::0;;48405:105::o;49024:709::-;49202:20;49224:19;39546:6;;39556:1;39546:11;39538:34;;;;-1:-1:-1;;;39538:34:0;;5814:2:1;39538:34:0;;;5796:21:1;5853:2;5833:18;;;5826:30;-1:-1:-1;;;5872:18:1;;;5865:40;5922:18;;39538:34:0;;;;;;;;;39594:1;39585:10;;49256:25:::1;49269:4:::0;49275:5;49256:12:::1;:25::i;:::-;49309:13:::0;;-1:-1:-1;;;;;49309:22:0::1;35650:42:::0;38405:52;;49344:313:::1;;49387:7;::::0;-1:-1:-1;;;;;49387:7:0::1;49375:64;;49418:21;;-1:-1:-1::0;;;49418:21:0::1;;;;;;;;;;;49375:64;49454:7;::::0;49568:11:::1;::::0;::::1;::::0;49616:13;;49454:191:::1;::::0;-1:-1:-1;;;49454:191:0;;49493:10:::1;49454:191;::::0;::::1;6243:34:1::0;-1:-1:-1;;;;;6313:15:1;;;6293:18;;;6286:43;6365:15;;;6345:18;;;6338:43;6417:15;;;6397:18;;;6390:43;49454:7:0;::::1;::::0;:20:::1;::::0;6154:19:1;;49454:191:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;49344:313;49697:28;49703:8;49713:4;49719:5;49697;:28::i;:::-;39631:1:::0;39622:6;:10;49667:58;;;;-1:-1:-1;49024:709:0;-1:-1:-1;;;;;49024:709:0:o;913:233::-;979:14;;-1:-1:-1;;;;;979:14:0;965:10;:28;961:55;;1002:14;;-1:-1:-1;;;1002:14:0;;;;;;;;;;;961:55;1052:14;;;1045:5;;1032:35;;-1:-1:-1;;;;;1052:14:0;;;;1045:5;;;;1032:35;;;1086:14;;;;1078:22;;-1:-1:-1;;1078:22:0;;;-1:-1:-1;;;;;1086:14:0;;1078:22;;;;1111:27;;;913:233::o;49741:965::-;50028:20;50050:19;39546:6;;39556:1;39546:11;39538:34;;;;-1:-1:-1;;;39538:34:0;;5814:2:1;39538:34:0;;;5796:21:1;5853:2;5833:18;;;5826:30;-1:-1:-1;;;5872:18:1;;;5865:40;5922:18;;39538:34:0;5612:334:1;39538:34:0;39594:1;39585:10;;50082:25:::1;50095:4:::0;50101:5;50082:12:::1;:25::i;:::-;50135:13:::0;;-1:-1:-1;;;;;50135:22:0::1;35650:42:::0;38405:52;;50170:460:::1;;50213:7;::::0;-1:-1:-1;;;;;50213:7:0::1;50201:64;;50244:21;;-1:-1:-1::0;;;50244:21:0::1;;;;;;;;;;;50201:64;50316:4;50284:20;::::0;;;::::1;::::0;::::1;;:::i;:::-;-1:-1:-1::0;;;;;50284:37:0::1;;50280:66;;50330:16;;-1:-1:-1::0;;;50330:16:0::1;;;;;;;;;;;50280:66;50361:7;::::0;:51:::1;::::0;-1:-1:-1;;;50361:51:0;;-1:-1:-1;;;;;50361:7:0;;::::1;::::0;:14:::1;::::0;:51:::1;::::0;50376:10:::1;::::0;50388:12;;50402:9;;;;50361:51:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;;50427:7:0::1;::::0;50541:11:::1;::::0;::::1;::::0;50589:13;;50427:191:::1;::::0;-1:-1:-1;;;50427:191:0;;50466:10:::1;50427:191;::::0;::::1;6243:34:1::0;-1:-1:-1;;;;;6313:15:1;;;6293:18;;;6286:43;6365:15;;;6345:18;;;6338:43;6417:15;;;6397:18;;;6390:43;50427:7:0;::::1;::::0;-1:-1:-1;50427:20:0::1;::::0;-1:-1:-1;6154:19:1;;50427:191:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;50170:460;50670:28;50676:8;50686:4;50692:5;50670;:28::i;:::-;39631:1:::0;39622:6;:10;50640:58;;;;-1:-1:-1;49741:965:0;-1:-1:-1;;;;;;;;49741:965:0:o;48266:131::-;588:5;;-1:-1:-1;;;;;588:5:0;574:10;:19;570:47;;602:15;;-1:-1:-1;;;602:15:0;;;;;;;;;;;570:47;48352:37:::1;-1:-1:-1::0;;;;;48352:17:0;::::1;48370:10;48382:6:::0;48352:17:::1;:37::i;:::-;48266:131:::0;;:::o;756:149::-;588:5;;-1:-1:-1;;;;;588:5:0;574:10;:19;570:47;;602:15;;-1:-1:-1;;;602:15:0;;;;;;;;;;;570:47;833:14:::1;:27:::0;;-1:-1:-1;;833:27:0::1;-1:-1:-1::0;;;;;833:27:0;::::1;::::0;;::::1;::::0;;;876:21:::1;::::0;::::1;::::0;-1:-1:-1;;876:21:0::1;756:149:::0;:::o;48518:498::-;48685:20;48707:19;39546:6;;39556:1;39546:11;39538:34;;;;-1:-1:-1;;;39538:34:0;;5814:2:1;39538:34:0;;;5796:21:1;5853:2;5833:18;;;5826:30;-1:-1:-1;;;5872:18:1;;;5865:40;5922:18;;39538:34:0;5612:334:1;39538:34:0;39594:1;39585:10;;48739:25:::1;48752:4:::0;48758:5;48739:12:::1;:25::i;:::-;48792:13:::0;;-1:-1:-1;;;;;48792:22:0::1;35650:42:::0;38405:52;;48827:113:::1;;48916:11;::::0;::::1;::::0;48858:13;;:70:::1;::::0;-1:-1:-1;;;;;48858:26:0;;::::1;::::0;48885:10:::1;::::0;48905:8;;48858:26:::1;:70::i;50714:344::-:0;50809:4;:20;;;50833:1;50809:25;50805:59;;50843:21;;-1:-1:-1;;;50843:21:0;;;;;;;;;;;50805:59;50879:5;:12;50895:1;50879:17;50875:46;;50905:16;;-1:-1:-1;;;50905:16:0;;;;;;;;;;;50875:46;50949:13;;-1:-1:-1;;;;;50949:22:0;35650:42;38405:52;;50988:36;;;;;51013:4;:11;;;51001:9;:23;50988:36;50984:66;;;51033:17;;-1:-1:-1;;;51033:17:0;;;;;;;;;;;50984:66;50794:264;50714:344;;:::o;51066:1107::-;51287:13;;;;51333:16;;;;51213:20;;;;;;-1:-1:-1;;;;;51333:30:0;;:62;;51379:4;:16;;;51333:62;;;51366:10;51333:62;51311:84;-1:-1:-1;51406:25:0;51434:31;-1:-1:-1;;;;;51434:18:0;;51311:84;51434:18;:31::i;:::-;51406:59;;51478:21;51517:8;-1:-1:-1;;;;;51517:15:0;;51535:10;51547:4;51553:5;51502:58;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;51478:82;;51572:12;51586:23;51621:8;-1:-1:-1;;;;;51613:22:0;51643:9;51654:8;51613:50;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;51571:92;;;;51679:7;51674:129;;51765:10;51759:17;51754:2;51742:10;51738:19;51731:46;51674:129;51829:11;;;;;-1:-1:-1;51851:23:0;51877:31;-1:-1:-1;;;;;51877:18:0;;51896:11;51877:18;:31::i;:::-;51851:57;-1:-1:-1;51934:35:0;51952:17;51851:57;51934:35;:::i;:::-;51919:50;;52001:4;:20;;;51986:12;:35;51982:79;;;52030:31;;-1:-1:-1;;;52030:31:0;;;;;;;;;;;51982:79;52096:13;;52111;;;;;52139:11;;;;;52079:86;;;52084:10;10342:34:1;;-1:-1:-1;;;;;10412:15:1;;;10392:18;;;10385:43;;;;10464:15;;;10444:18;;;10437:43;10516:15;;;10496:18;;;10489:43;10563:3;10548:19;;10541:35;;;;10607:3;10592:19;;10585:35;;;52079:86:0;;;;;;;10268:3:1;52079:86:0;;;51256:917;;;;;;;51066:1107;;;;;;:::o;36894:261::-;35650:42;-1:-1:-1;;;;;36983:17:0;;38405:52;36979:169;;37019:26;-1:-1:-1;;;;;37019:18:0;;37038:6;37019:18;:26::i;36979:169::-;37078:58;-1:-1:-1;;;;;37078:46:0;;37125:2;37129:6;37078:46;:58::i;37163:292::-;35650:42;-1:-1:-1;;;;;37270:17:0;;38405:52;37266:182;;37313:22;;-1:-1:-1;;;37313:22:0;;;;;;;;;;;37266:182;37368:68;-1:-1:-1;;;;;37368:50:0;;37419:4;37425:2;37429:6;37368:50;:68::i;:::-;37163:292;;;;:::o;37883:265::-;37959:7;35650:42;-1:-1:-1;;;;;37983:17:0;;38405:52;37979:162;;-1:-1:-1;;;;;;38026:13:0;;;38019:20;;37979:162;38079:50;;-1:-1:-1;;;38079:50:0;;-1:-1:-1;;;;;683:55:1;;;38079:50:0;;;665:74:1;38079:43:0;;;;;638:18:1;;38079:50:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;38072:57;;37979:162;37883:265;;;;:::o;29844:349::-;29917:12;30121:1;30118;30115;30112;30104:6;30100:2;30093:5;30088:35;30077:46;;30154:7;30146:39;;;;-1:-1:-1;;;30146:39:0;;11022:2:1;30146:39:0;;;11004:21:1;11061:2;11041:18;;;11034:30;11100:21;11080:18;;;11073:49;11139:18;;30146:39:0;10820:343:1;16993:162:0;17103:43;;-1:-1:-1;;;;;11360:55:1;;;17103:43:0;;;11342:74:1;11432:18;;;11425:34;;;17076:71:0;;17096:5;;17118:14;;;;;11315:18:1;;17103:43:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;17076:19;:71::i;17400:190::-;17528:53;;-1:-1:-1;;;;;11751:15:1;;;17528:53:0;;;11733:34:1;11803:15;;;11783:18;;;11776:43;11835:18;;;11828:34;;;17501:81:0;;17521:5;;17543:18;;;;;11645::1;;17528:53:0;11470:398:1;20458:638:0;20882:23;20908:33;-1:-1:-1;;;;;20908:27:0;;20936:4;20908:27;:33::i;:::-;20882:59;;20956:10;:17;20977:1;20956:22;;:57;;;;;20994:10;20983:30;;;;;;;;;;;;:::i;:::-;20982:31;20956:57;20952:137;;;21037:40;;-1:-1:-1;;;21037:40:0;;-1:-1:-1;;;;;683:55:1;;21037:40:0;;;665:74:1;638:18;;21037:40:0;492:253:1;9124:168:0;9199:12;9231:53;9253:6;9261:4;9267:1;9270:13;9231:21;:53::i;15264:82::-;15321:17;;-1:-1:-1;;;15321:17:0;;;;;;;;;;;10783:494;10964:12;11017:5;10993:21;:29;10989:110;;;11046:41;;-1:-1:-1;;;11046:41:0;;11081:4;11046:41;;;665:74:1;638:18;;11046:41:0;492:253:1;10989:110:0;11110:12;11124:23;11151:6;-1:-1:-1;;;;;11151:11:0;11170:5;11177:4;11151:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;11109:73;;;;11200:69;11227:6;11235:7;11244:10;11256:12;11200:26;:69::i;:::-;11193:76;;;;10783:494;;;;;;;:::o;13374:710::-;13570:12;13599:7;13595:482;;;13627:10;:17;13648:1;13627:22;13623:345;;13854:6;-1:-1:-1;;;;;13854:18:0;;13876:1;13854:23;13850:103;;13909:24;;-1:-1:-1;;;13909:24:0;;-1:-1:-1;;;;;683:55:1;;13909:24:0;;;665:74:1;638:18;;13909:24:0;492:253:1;13850:103:0;-1:-1:-1;13989:10:0;13982:17;;13595:482;14032:33;14040:10;14052:12;15526:17;;:21;15522:421;;15758:10;15752:17;15815:15;15802:10;15798:2;15794:19;15787:44;15522:421;15878:14;:12;:14;;:::i;14:174:1:-;-1:-1:-1;;;;;113:5:1;109:54;102:5;99:65;89:93;;178:1;175;168:12;89:93;14:174;:::o;193:294::-;279:6;332:2;320:9;311:7;307:23;303:32;300:52;;;348:1;345;338:12;300:52;387:9;374:23;406:51;451:5;406:51;:::i;:::-;476:5;193:294;-1:-1:-1;;;193:294:1:o;750:127::-;811:10;806:3;802:20;799:1;792:31;842:4;839:1;832:15;866:4;863:1;856:15;882:959;944:5;992:4;980:9;975:3;971:19;967:30;964:50;;;1010:1;1007;1000:12;964:50;1043:2;1037:9;1085:4;1077:6;1073:17;1156:6;1144:10;1141:22;1120:18;1108:10;1105:34;1102:62;1099:88;;;1167:18;;:::i;:::-;1203:2;1196:22;1236:6;-1:-1:-1;1236:6:1;1266:23;;1298:53;1266:23;1298:53;:::i;:::-;1360:23;;1435:2;1420:18;;1407:32;1448:53;1407:32;1448:53;:::i;:::-;1529:2;1517:15;;1510:32;1594:2;1579:18;;1566:32;1607:53;1566:32;1607:53;:::i;:::-;1693:7;1688:2;1680:6;1676:15;1669:32;;1762:2;1751:9;1747:18;1734:32;1729:2;1721:6;1717:15;1710:57;1829:3;1818:9;1814:19;1801:33;1795:3;1787:6;1783:16;1776:59;;882:959;;;;:::o;1846:718::-;1888:5;1941:3;1934:4;1926:6;1922:17;1918:27;1908:55;;1959:1;1956;1949:12;1908:55;1995:6;1982:20;2021:18;2058:2;2054;2051:10;2048:36;;;2064:18;;:::i;:::-;2139:2;2133:9;2107:2;2193:13;;-1:-1:-1;;2189:22:1;;;2213:2;2185:31;2181:40;2169:53;;;2237:18;;;2257:22;;;2234:46;2231:72;;;2283:18;;:::i;:::-;2323:10;2319:2;2312:22;2358:2;2350:6;2343:18;2404:3;2397:4;2392:2;2384:6;2380:15;2376:26;2373:35;2370:55;;;2421:1;2418;2411:12;2370:55;2485:2;2478:4;2470:6;2466:17;2459:4;2451:6;2447:17;2434:54;2532:1;2525:4;2520:2;2512:6;2508:15;2504:26;2497:37;2552:6;2543:15;;;;;;1846:718;;;;:::o;2569:637::-;2717:6;2725;2733;2786:3;2774:9;2765:7;2761:23;2757:33;2754:53;;;2803:1;2800;2793:12;2754:53;2842:9;2829:23;2861:51;2906:5;2861:51;:::i;:::-;2931:5;-1:-1:-1;2955:62:1;3009:7;3004:2;2989:18;;2955:62;:::i;:::-;2945:72;;3068:3;3057:9;3053:19;3040:33;3096:18;3088:6;3085:30;3082:50;;;3128:1;3125;3118:12;3082:50;3151:49;3192:7;3183:6;3172:9;3168:22;3151:49;:::i;:::-;3141:59;;;2569:637;;;;;:::o;3464:1271::-;3673:6;3681;3689;3697;3705;3713;3757:9;3748:7;3744:23;3787:3;3783:2;3779:12;3776:32;;;3804:1;3801;3794:12;3776:32;3843:9;3830:23;3862:51;3907:5;3862:51;:::i;:::-;3932:5;-1:-1:-1;3956:62:1;4010:7;4005:2;3990:18;;3956:62;:::i;:::-;3946:72;;4069:3;4058:9;4054:19;4041:33;4093:18;4134:2;4126:6;4123:14;4120:34;;;4150:1;4147;4140:12;4120:34;4173:49;4214:7;4205:6;4194:9;4190:22;4173:49;:::i;:::-;4163:59;-1:-1:-1;4257:3:1;-1:-1:-1;;4238:17:1;;4234:27;4231:47;;;4274:1;4271;4264:12;4231:47;4312:3;4301:9;4297:19;4287:29;;4369:3;4358:9;4354:19;4341:33;4325:49;;4399:2;4389:8;4386:16;4383:36;;;4415:1;4412;4405:12;4383:36;4453:8;4442:9;4438:24;4428:34;;4500:7;4493:4;4489:2;4485:13;4481:27;4471:55;;4522:1;4519;4512:12;4471:55;4562:2;4549:16;4535:30;;4588:2;4580:6;4577:14;4574:34;;;4604:1;4601;4594:12;4574:34;;4649:7;4644:2;4635:6;4631:2;4627:15;4623:24;4620:37;4617:57;;;4670:1;4667;4660:12;4617:57;4701:2;4697;4693:11;4683:21;;4723:6;4713:16;;;;3464:1271;;;;;;;;:::o;4971:364::-;5068:6;5076;5129:2;5117:9;5108:7;5104:23;5100:32;5097:52;;;5145:1;5142;5135:12;5097:52;5184:9;5171:23;5203:51;5248:5;5203:51;:::i;:::-;5273:5;5325:2;5310:18;;;;5297:32;;-1:-1:-1;;;4971:364:1:o;6444:167::-;6511:20;;6571:14;6560:26;;6550:37;;6540:65;;6601:1;6598;6591:12;6540:65;6444:167;;;:::o;6616:266::-;6704:6;6699:3;6692:19;6756:6;6749:5;6742:4;6737:3;6733:14;6720:43;-1:-1:-1;6808:1:1;6783:16;;;6801:4;6779:27;;;6772:38;;;;6864:2;6843:15;;;-1:-1:-1;;6839:29:1;6830:39;;;6826:50;;6616:266::o;6887:1292::-;7125:4;7154:3;-1:-1:-1;;;;;7257:2:1;7249:6;7245:15;7234:9;7227:34;7296:6;7283:20;7312:51;7357:5;7312:51;:::i;:::-;7410:2;7403:5;7399:14;7394:2;7383:9;7379:18;7372:42;;7463:2;7455:6;7451:15;7438:29;7476:53;7521:7;7476:53;:::i;:::-;7578:2;7569:7;7565:16;7560:2;7549:9;7545:18;7538:44;;7611:34;7641:2;7633:6;7629:15;7611:34;:::i;:::-;7664:14;7732:2;7718:12;7714:21;7709:2;7698:9;7694:18;7687:49;7813:2;7777:34;7807:2;7799:6;7795:15;7777:34;:::i;:::-;7773:43;7767:3;7756:9;7752:19;7745:72;;;7866:3;7858:6;7854:16;7841:30;7880:53;7925:7;7880:53;:::i;:::-;7983:2;7974:7;7970:16;7964:3;7953:9;7949:19;7942:45;;;8049:3;8041:6;8037:16;8024:30;8018:3;8007:9;8003:19;7996:59;8092:2;8086:3;8075:9;8071:19;8064:31;8112:61;8169:2;8158:9;8154:18;8146:6;8138;8112:61;:::i;:::-;8104:69;6887:1292;-1:-1:-1;;;;;;;6887:1292:1:o;8184:250::-;8269:1;8279:113;8293:6;8290:1;8287:13;8279:113;;;8369:11;;;8363:18;8350:11;;;8343:39;8315:2;8308:10;8279:113;;;-1:-1:-1;;8426:1:1;8408:16;;8401:27;8184:250::o;8439:970::-;8671:4;-1:-1:-1;;;;;8781:2:1;8773:6;8769:15;8758:9;8751:34;8840:2;8831:6;8825:13;8821:22;8816:2;8805:9;8801:18;8794:50;8908:2;8902;8894:6;8890:15;8884:22;8880:31;8875:2;8864:9;8860:18;8853:59;8976:2;8970;8962:6;8958:15;8952:22;8948:31;8943:2;8932:9;8928:18;8921:59;;9035:2;9027:6;9023:15;9017:22;9011:3;9000:9;8996:19;8989:51;9095:3;9087:6;9083:16;9077:23;9071:3;9060:9;9056:19;9049:52;9138:3;9132;9121:9;9117:19;9110:32;9171:6;9165:13;9215:6;9209:3;9198:9;9194:19;9187:35;9241:3;9253:79;9325:6;9320:2;9309:9;9305:18;9300:2;9292:6;9288:15;9253:79;:::i;:::-;9400:2;9393;9389:7;9384:2;9376:6;9372:15;9368:29;9357:9;9353:45;9349:54;9341:62;;;;8439:970;;;;;;:::o;9414:287::-;9543:3;9581:6;9575:13;9597:66;9656:6;9651:3;9644:4;9636:6;9632:17;9597:66;:::i;:::-;9679:16;;;;;9414:287;-1:-1:-1;;9414:287:1:o;9706:225::-;9773:9;;;9794:11;;;9791:134;;;9847:10;9842:3;9838:20;9835:1;9828:31;9882:4;9879:1;9872:15;9910:4;9907:1;9900:15;10631:184;10701:6;10754:2;10742:9;10733:7;10729:23;10725:32;10722:52;;;10770:1;10767;10760:12;10722:52;-1:-1:-1;10793:16:1;;10631:184;-1:-1:-1;10631:184:1:o;11873:277::-;11940:6;11993:2;11981:9;11972:7;11968:23;11964:32;11961:52;;;12009:1;12006;11999:12;11961:52;12041:9;12035:16;12094:5;12087:13;12080:21;12073:5;12070:32;12060:60;;12116:1;12113;12106:12

Swarm Source

ipfs://f9c1febef50be336455a65e4dfce5ebff83f15768330c89ca972e718d65e80ed

Block Transaction Gas Used Reward
view all blocks collator

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