MNT Price: $0.91 (+1.79%)

Contract

0xe38488b1eD1b4faC36C6D27879569aa282E46443
 

Overview

MNT Balance

Mantle Mainnet Network LogoMantle Mainnet Network LogoMantle Mainnet Network Logo0 MNT

MNT Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To
Swap Meta759512012025-02-20 6:25:14342 days ago1740032714IN
0xe38488b1...282E46443
0 MNT0.030333250.02
Swap Meta759510732025-02-20 6:20:58342 days ago1740032458IN
0xe38488b1...282E46443
0 MNT0.014977350.02
Swap Meta759508272025-02-20 6:12:46342 days ago1740031966IN
0xe38488b1...282E46443
0 MNT0.106761250.02
Swap Meta758225842025-02-17 6:58:00345 days ago1739775480IN
0xe38488b1...282E46443
0 MNT0.265600320.02
Swap Meta755823992025-02-11 17:31:50351 days ago1739295110IN
0xe38488b1...282E46443
0 MNT0.017277170.02
Swap Meta754194522025-02-07 23:00:16354 days ago1738969216IN
0xe38488b1...282E46443
0 MNT0.033608790.02
Swap Meta754189642025-02-07 22:44:00354 days ago1738968240IN
0xe38488b1...282E46443
0 MNT0.044714980.02
Swap Meta753293442025-02-05 20:56:40356 days ago1738789000IN
0xe38488b1...282E46443
0 MNT0.015370140.02
Swap Meta751058212025-01-31 16:45:54362 days ago1738341954IN
0xe38488b1...282E46443
0 MNT0.123186910.04
Swap Meta751058062025-01-31 16:45:24362 days ago1738341924IN
0xe38488b1...282E46443
0 MNT0.171625090.04
Swap Meta751057872025-01-31 16:44:46362 days ago1738341886IN
0xe38488b1...282E46443
0 MNT0.066769620.04
Swap Meta751027622025-01-31 15:03:56362 days ago1738335836IN
0xe38488b1...282E46443
5 MNT0.054733690.03
Swap Meta750994792025-01-31 13:14:30362 days ago1738329270IN
0xe38488b1...282E46443
0 MNT0.019192640.02
Swap Meta750903472025-01-31 8:10:06362 days ago1738311006IN
0xe38488b1...282E46443
0 MNT0.02296880.02
Swap Meta750761322025-01-31 0:16:16362 days ago1738282576IN
0xe38488b1...282E46443
0 MNT0.126166610.02
Swap Meta750760582025-01-31 0:13:48362 days ago1738282428IN
0xe38488b1...282E46443
0 MNT0.117202930.02
Swap Meta750760012025-01-31 0:11:54362 days ago1738282314IN
0xe38488b1...282E46443
0 MNT0.028798510.02
Swap Meta750709762025-01-30 21:24:24362 days ago1738272264IN
0xe38488b1...282E46443
0 MNT0.352757640.03
Swap Meta750708992025-01-30 21:21:50362 days ago1738272110IN
0xe38488b1...282E46443
0 MNT0.355563810.03
Swap Meta750706852025-01-30 21:14:42362 days ago1738271682IN
0xe38488b1...282E46443
0 MNT0.247889660.03
Swap Meta750507562025-01-30 10:10:24363 days ago1738231824IN
0xe38488b1...282E46443
0 MNT0.154400440.03
Swap Meta750507312025-01-30 10:09:34363 days ago1738231774IN
0xe38488b1...282E46443
0 MNT0.13719060.03
Swap Meta750505872025-01-30 10:04:46363 days ago1738231486IN
0xe38488b1...282E46443
0 MNT0.225929020.03
Swap Meta750417622025-01-30 5:10:36363 days ago1738213836IN
0xe38488b1...282E46443
0 MNT0.029244690.02
Swap Meta750159282025-01-29 14:49:28364 days ago1738162168IN
0xe38488b1...282E46443
0 MNT0.247157190.03
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To
751027622025-01-31 15:03:56362 days ago1738335836
0xe38488b1...282E46443
5 MNT
749707962025-01-28 13:45:04365 days ago1738071904
0xe38488b1...282E46443
0.1 MNT
749539712025-01-28 4:24:14365 days ago1738038254
0xe38488b1...282E46443
20 MNT
749343152025-01-27 17:29:02366 days ago1737998942
0xe38488b1...282E46443
8 MNT
749342922025-01-27 17:28:16366 days ago1737998896
0xe38488b1...282E46443
105 MNT
749024802025-01-26 23:47:52366 days ago1737935272
0xe38488b1...282E46443
100 MNT
747870222025-01-24 7:39:16369 days ago1737704356
0xe38488b1...282E46443
50 MNT
747774332025-01-24 2:19:38369 days ago1737685178
0xe38488b1...282E46443
16.9 MNT
747491342025-01-23 10:36:20370 days ago1737628580
0xe38488b1...282E46443
1 MNT
747128922025-01-22 14:28:16371 days ago1737556096
0xe38488b1...282E46443
45 MNT
746826742025-01-21 21:41:00371 days ago1737495660
0xe38488b1...282E46443
209 MNT
746150182025-01-20 8:05:48373 days ago1737360348
0xe38488b1...282E46443
60 MNT
745889292025-01-19 17:36:10374 days ago1737308170
0xe38488b1...282E46443
55 MNT
745803232025-01-19 12:49:18374 days ago1737290958
0xe38488b1...282E46443
14.4 MNT
745802922025-01-19 12:48:16374 days ago1737290896
0xe38488b1...282E46443
18 MNT
745802452025-01-19 12:46:42374 days ago1737290802
0xe38488b1...282E46443
36.2 MNT
745802032025-01-19 12:45:18374 days ago1737290718
0xe38488b1...282E46443
35.5 MNT
745034842025-01-17 18:08:00376 days ago1737137280
0xe38488b1...282E46443
25 MNT
745000892025-01-17 16:14:50376 days ago1737130490
0xe38488b1...282E46443
1 MNT
744977932025-01-17 14:58:18376 days ago1737125898
0xe38488b1...282E46443
1 MNT
744866332025-01-17 8:46:18376 days ago1737103578
0xe38488b1...282E46443
671 MNT
744866222025-01-17 8:45:56376 days ago1737103556
0xe38488b1...282E46443
671 MNT
744800682025-01-17 5:07:28376 days ago1737090448
0xe38488b1...282E46443
13 MNT
744800042025-01-17 5:05:20376 days ago1737090320
0xe38488b1...282E46443
3.41 MNT
744461222025-01-16 10:15:56377 days ago1737022556
0xe38488b1...282E46443
0.1 MNT
View All Internal Transactions

Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
DeltaMetaAggregator

Compiler Version
v0.8.28+commit.7893614a

Optimization Enabled:
Yes with 1000000 runs

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

pragma solidity ^0.8.28;

import {PermitUtilsSlim} from "./permit/PermitUtilsSlim.sol";

////////////////////////////////////////////////////
// Minimal meta swap aggregation contract
// - Allows simulation to validate receiver amount
// - Supports permits, exact in & out swaps
// - Swap aggregation calls are assumed to already
//   check for slippage and send funds directly to the
//   user-defined receiver
////////////////////////////////////////////////////
contract DeltaMetaAggregator is PermitUtilsSlim {
    ////////////////////////////////////////////////////
    // Errors
    ////////////////////////////////////////////////////
    error SimulationResults(uint256 amountPaid, uint256 amountReceived, bytes errorData);
    error InvalidSwapCall();
    error NativeTransferFailed();
    error HasNoMsgValue();

    // NativeTransferFailed()
    bytes4 private constant NATIVE_TRANSFER_FAILED = 0xf4b3b1bc;
    // InvalidSwapCall()
    bytes4 private constant INVALID_SWAP_CALL = 0xee68db59;
    // HasNoMsgValue()
    bytes4 private constant HAS_NO_MSG_VALUE = 0x07270ad5;

    ////////////////////////////////////////////////////
    // State
    ////////////////////////////////////////////////////

    /// @notice maps token to approvalTarget to bool
    mapping(address => mapping(address => bool)) private _approvedTargets;

    ////////////////////////////////////////////////////
    // Constants
    ////////////////////////////////////////////////////

    /// @dev maximum uint256 - used for approvals
    uint256 private constant MAX_UINT_256 = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;

    /// @dev mask for selector in calldata
    bytes32 private constant SELECTOR_MASK = 0xffffffff00000000000000000000000000000000000000000000000000000000;

    /// @dev mask for address in encoded input data
    uint256 private constant ADDRESS_MASK = 0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff;

    /// @dev high bit for sweep flag
    uint256 private constant SWEEP_MASK = 1 << 255;

    ////////////////////////////////////////////////////
    // Constructor
    ////////////////////////////////////////////////////

    constructor() {}

    ////////////////////////////////////////////////////
    // Receive function for native swaps
    ////////////////////////////////////////////////////

    receive() external payable {}

    ////////////////////////////////////////////////////
    // Swap functions
    ////////////////////////////////////////////////////

    /**
     * Executes meta aggregation swap.
     * Can only be executed any address but Permit2.
     * Calldata is validated to prevent illegitimate `transferFrom`
     * Note that the receiver address must be manually set in
     * the aggregation call, otherwise, the funds will remain in this contract
     * Ideally this function is executed after an simulation via `simSwapMeta`
     * @param permitData permit calldata (use empty data for plai transfers)
     * @param swapData swap calldata
     * @param assetInData token input address, use zero address for native - high bit signals that we have to sweep
     * @param assetOutData token output address, use zero address for native - high bit signals that we have to sweep, the address is ignored if sweep flag is not set
     * @param amountIn input amount, ignored for native transfer
     * @param approvalTarget contract approves this target when swapping (only if allowance too low)
     * @param swapTarget swap aggregation executor
     * @param receiver of assetOut - ignored if assetOut sweep flag is set to false
     */
    function swapMeta(
        bytes calldata permitData,
        bytes calldata swapData,
        bytes32 assetInData,
        bytes32 assetOutData,
        uint256 amountIn,
        address approvalTarget,
        address swapTarget,
        address receiver
    ) external payable {
        (address asset, bool sweep) = _decodeAssetData(assetInData);
        // zero address assumes native transfer
        if (asset != address(0)) {
            // permit and pull - checks that no native is attached
            _permitAndPull(asset, amountIn, permitData);

            // approve if no allowance
            // we actually do not care what we approve as this
            // contract is not supposed to hold balances
            _approveIfNot(asset, approvalTarget);
        } else {
            // if native is the input asset,
            // we enforce that msg.value is attached
            _requireHasMsgValue();
        }

        // validate swap call
        _validateCalldata(swapData, swapTarget);

        // execute external call
        _executeExternalCall(swapData, swapTarget);

        // execute sweep of input asset if desired
        _sweepTokenIfNeeded(sweep, asset);

        // execute sweep of output asset if desired
        _handleOutputAsset(assetOutData, receiver);
    }

    struct SimAmounts {
        address payAsset;
        address receiveAsset;
        uint256 amountReceived;
        uint256 amountPaid;
    }

    /**
     * Simulates the swap aggregation. Should be called before `swapMeta`
     * Always reverts with simulation results in custom error.
     * Ideally called via staticcall, the return object contains
     * the balance change of the `receiver` address.
     * Parameters are otherwise identical to `swapMeta`.
     */
    function simSwapMeta(
        bytes calldata permitData,
        bytes calldata swapData,
        bytes32 assetInData,
        bytes32 assetOutData,
        uint256 amountIn,
        address approvalTarget,
        address swapTarget,
        address receiver
    ) external payable {
        // we use a struct to avoid stack too deep
        SimAmounts memory simAmounts;
        // read asset data
        (simAmounts.payAsset, ) = _decodeAssetData(assetInData);
        (simAmounts.receiveAsset, ) = _decodeAssetData(assetOutData);

        // get initial balances of receiver
        simAmounts.amountReceived = _balanceOf(simAmounts.receiveAsset, receiver);
        simAmounts.amountPaid = _balanceOf(simAmounts.payAsset, msg.sender);

        // narrow scope for stack too deep
        {
            (bool success, bytes memory returnData) = address(this).delegatecall(
                abi.encodeWithSelector(
                    DeltaMetaAggregator.swapMeta.selector, // call swap meta on sel
                    permitData,
                    swapData,
                    assetInData,
                    assetOutData,
                    amountIn,
                    approvalTarget,
                    swapTarget,
                    receiver
                )
            );
            if (!success) {
                revert SimulationResults(0, 0, returnData);
            }
        }

        // get post swap balances
        simAmounts.amountReceived = _balanceOf(simAmounts.receiveAsset, receiver) - simAmounts.amountReceived;
        simAmounts.amountPaid = simAmounts.amountPaid - _balanceOf(simAmounts.payAsset, msg.sender);
        revert SimulationResults(simAmounts.amountPaid, simAmounts.amountReceived, "");
    }

    ////////////////////////////////////////////////////
    // Internals
    ////////////////////////////////////////////////////

    /// @dev executes call on target with data
    ///      -> MUST validate the selector and target first
    /// @param data calldata
    /// @param target target address
    function _executeExternalCall(bytes calldata data, address target) private {
        assembly {
            let ptr := mload(0x40)
            calldatacopy(ptr, data.offset, data.length) // copy permit calldata
            if iszero(
                call(
                    gas(),
                    target,
                    callvalue(),
                    ptr, //
                    data.length, // the length must be correct or the call will fail
                    0x0, // output = empty
                    0x0 // output size = zero
                )
            ) {
                returndatacopy(0, 0, returndatasize())
                revert(0, returndatasize())
            }
        }
    }

    /// @dev checks that
    ///     - Permit2 cannot be called
    ///     - the selector cannot be IERC20.transferFrom
    function _validateCalldata(bytes calldata data, address swapTarget) private pure {
        assembly {
            // extract the selector from the calldata
            let selector := and(SELECTOR_MASK, calldataload(data.offset))

            // check if it is `transferFrom`
            if eq(selector, ERC20_TRANSFER_FROM) {
                mstore(0x0, INVALID_SWAP_CALL)
                revert(0x0, 0x4)
            }
            // check if the target is permit2
            if eq(swapTarget, PERMIT2) {
                mstore(0x0, INVALID_SWAP_CALL)
                revert(0x0, 0x4)
            }
        }
    }

    /// @dev enforce that msg.value is provided
    function _requireHasMsgValue() private view {
        assembly {
            if iszero(callvalue()) {
                mstore(0x0, HAS_NO_MSG_VALUE)
                revert(0x0, 0x4)
            }
        }
    }

    /// @dev decode asset data to asset address and sweep flag
    function _decodeAssetData(bytes32 data) private pure returns (address asset, bool sweep) {
        assembly {
            asset := and(ADDRESS_MASK, data)
            sweep := and(SWEEP_MASK, data)
        }
    }

    /// @dev Checks approvals in storage and sets the allowance to the
    ///      maximum if the current approval is not already >= an amount.
    ///      Reverts if the return data is invalid or the call reverts.
    /// @param token The address of the token contract.
    /// @param spender The address that receives an allowance.
    function _approveIfNot(address token, address spender) private {
        // approve if necessary
        if (!_approvedTargets[token][spender]) {
            assembly {
                let ptr := mload(0x40)
                ////////////////////////////////////////////////////
                // Approve, at this point it is clear that the target is nonzero
                ////////////////////////////////////////////////////
                // selector for approve(address,uint256)
                mstore(ptr, ERC20_APPROVE)
                mstore(add(ptr, 0x04), spender)
                mstore(add(ptr, 0x24), MAX_UINT_256)

                if iszero(call(gas(), token, 0x0, ptr, 0x44, ptr, 32)) {
                    revert(0x0, 0x0)
                }
            }
            _approvedTargets[token][spender] = true;
        }
    }

    /// @dev balanceOf call in assembly, compatible for both native (use address zero for underlying) and ERC20
    function _balanceOf(address underlying, address entity) private view returns (uint256 entityBalance) {
        assembly {
            switch iszero(underlying)
            case 1 {
                entityBalance := balance(entity)
            }
            default {
                ////////////////////////////////////////////////////
                // get token balance in assembly usingn scrap space (64 bytes)
                ////////////////////////////////////////////////////

                // selector for balanceOf(address)
                mstore(0x0, ERC20_BALANCE_OF)
                // add this address as parameter
                mstore(0x4, entity)

                // call to underlying
                if iszero(staticcall(gas(), underlying, 0x0, 0x24, 0x0, 0x20)) {
                    revert(0x0, 0x0)
                }

                entityBalance := mload(0x0)
            }
        }
    }

    /// @dev sweep asset to caller if sweep=true
    function _sweepTokenIfNeeded(bool sweep, address token) private {
        assembly {
            if sweep {
                // initialize transferAmount
                switch iszero(token)
                case 1 {
                    let transferAmount := selfbalance()
                    if gt(transferAmount, 0) {
                        if iszero(
                            call(
                                gas(),
                                caller(),
                                transferAmount,
                                0x0, // input = empty for fallback/receive
                                0x0, // input size = zero
                                0x0, // output = empty
                                0x0 // output size = zero
                            )
                        ) {
                            mstore(0, NATIVE_TRANSFER_FAILED)
                            revert(0, 0x4) // revert when native transfer fails
                        }
                    }
                }
                default {
                    // selector for balanceOf(address)
                    mstore(0, ERC20_BALANCE_OF)
                    // add this address as parameter
                    mstore(0x04, address())
                    // call to token
                    pop(
                        staticcall(
                            gas(),
                            token,
                            0x0,
                            0x24,
                            0x0,
                            0x20 //
                        )
                    )
                    // load the retrieved balance
                    let transferAmount := mload(0x0)

                    if gt(transferAmount, 0) {
                        let ptr := mload(0x40) // free memory pointer

                        // selector for transfer(address,uint256)
                        mstore(ptr, ERC20_TRANSFER)
                        mstore(add(ptr, 0x04), caller())
                        mstore(add(ptr, 0x24), transferAmount)

                        let success := call(gas(), token, 0, ptr, 0x44, ptr, 32)

                        let rdsize := returndatasize()

                        // Check for ERC20 success. ERC20 tokens should return a boolean,
                        // but some don't. We accept 0-length return data as success, or at
                        // least 32 bytes that starts with a 32-byte boolean true.
                        success := and(
                            success, // call itself succeeded
                            or(
                                iszero(rdsize), // no return data, or
                                and(
                                    iszero(lt(rdsize, 32)), // at least 32 bytes
                                    eq(mload(ptr), 1) // starts with uint256(1)
                                )
                            )
                        )

                        if iszero(success) {
                            returndatacopy(ptr, 0, rdsize)
                            revert(ptr, rdsize)
                        }
                    }
                }
            }
        }
    }

    /// @dev sweep asset to receiver if sweep=true
    function _handleOutputAsset(bytes32 data, address receiver) private {
        assembly {
            if and(SWEEP_MASK, data) {
                let token := and(ADDRESS_MASK, data)
                // initialize transferAmount
                switch iszero(token)
                case 1 {
                    let transferAmount := selfbalance()
                    if gt(transferAmount, 0) {
                        if iszero(
                            call(
                                gas(),
                                receiver,
                                transferAmount,
                                0x0, // input = empty for fallback/receive
                                0x0, // input size = zero
                                0x0, // output = empty
                                0x0 // output size = zero
                            )
                        ) {
                            mstore(0, NATIVE_TRANSFER_FAILED)
                            revert(0, 0x4) // revert when native transfer fails
                        }
                    }
                }
                default {
                    // selector for balanceOf(address)
                    mstore(0, ERC20_BALANCE_OF)
                    // add this address as parameter
                    mstore(0x04, address())
                    // call to token
                    pop(
                        staticcall(
                            gas(),
                            token,
                            0x0,
                            0x24,
                            0x0,
                            0x20 //
                        )
                    )
                    // load the retrieved balance
                    let transferAmount := mload(0x0)

                    if gt(transferAmount, 0) {
                        let ptr := mload(0x40) // free memory pointer

                        // selector for transfer(address,uint256)
                        mstore(ptr, ERC20_TRANSFER)
                        mstore(add(ptr, 0x04), receiver)
                        mstore(add(ptr, 0x24), transferAmount)

                        let success := call(gas(), token, 0, ptr, 0x44, ptr, 32)

                        let rdsize := returndatasize()

                        // Check for ERC20 success. ERC20 tokens should return a boolean,
                        // but some don't. We accept 0-length return data as success, or at
                        // least 32 bytes that starts with a 32-byte boolean true.
                        success := and(
                            success, // call itself succeeded
                            or(
                                iszero(rdsize), // no return data, or
                                and(
                                    iszero(lt(rdsize, 32)), // at least 32 bytes
                                    eq(mload(ptr), 1) // starts with uint256(1)
                                )
                            )
                        )

                        if iszero(success) {
                            returndatacopy(ptr, 0, rdsize)
                            revert(ptr, rdsize)
                        }
                    }
                }
            }
        }
    }
}

File 2 of 4 : PermitConstants.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

/// @title PermitConstants
/// @notice A contract containing constants used for Permit2 & ERC20 type permits
abstract contract PermitConstants {
    /*//////////////////////////////////////////////////////////////
                                CONSTANTS
    //////////////////////////////////////////////////////////////*/

    /// @dev default Permit2 address
    address internal constant PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3; // solhint-disable-line var-name-mixedcase

    bytes32 internal constant ERC20_PERMIT = 0xd505accf00000000000000000000000000000000000000000000000000000000;
    bytes32 internal constant DAI_PERMIT = 0x8fcbaf0c00000000000000000000000000000000000000000000000000000000;
    bytes32 internal constant PERMIT2_PERMIT = 0x2b67b57000000000000000000000000000000000000000000000000000000000;
    bytes32 internal constant CREDIT_PERMIT = 0x0b52d55800000000000000000000000000000000000000000000000000000000;
    bytes32 internal constant PERMIT2_TRANSFER_FROM = 0x36c7851600000000000000000000000000000000000000000000000000000000;

    bytes4 internal constant _PERMIT_LENGTH_ERROR = 0x68275857; // SafePermitBadLength.selector
}

File 3 of 4 : PermitUtilsSlim.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {PermitConstants} from "./PermitConstants.sol";
import {ERC20Selectors} from "../selectors/ERC20Selectors.sol";

/// @title PermitUtilsSlim
/// @notice A contract containing utilities for Permits
abstract contract PermitUtilsSlim is PermitConstants, ERC20Selectors {

    /*//////////////////////////////////////////////////////////////
                                 ERRORS
    //////////////////////////////////////////////////////////////*/

    error SafePermitBadLength();
    error HasMsgValue();

    bytes4 internal constant HAS_MSG_VALUE = 0xf6a73902;

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

    constructor() { }

    /**
     * @notice The function attempts to call the permit function on a given ERC20 token and executes a transfer afterwards
     * @dev The function is designed to support a variety of permit functions, namely: IERC20Permit, IDaiLikePermit, and IPermit2.
     * It accommodates both Compact and Full formats of these permit types.
     * Please note, it is expected that the `expiration` parameter for the compact Permit2 and the `deadline` parameter
     * for the compact Permit are to be incremented by one before invoking this function. This approach is motivated by
     * gas efficiency considerations; as the unlimited expiration period is likely to be the most common scenario, and
     * zeros are cheaper to pass in terms of gas cost. Thus, callers should increment the expiration or deadline by one
     * before invocation for optimized performance.
     * Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of
     * the caller to make sure that the higher 96 bits of the `owner` and `spender` parameters are clean.
     * @param token The address of the ERC20 token on which to call the permit function.
     * @param amount Amount to pull from the caller - should be less than or equal the permit amount
     * @param permit The off-chain permit data, containing different fields depending on the type of permit function.
     */
    function _permitAndPull(address token, uint256 amount, bytes calldata permit) internal {
        assembly ("memory-safe") { // solhint-disable-line no-inline-assembly

            // revert if native value provided
            if gt(callvalue(), 0) {
                mstore(0x0, HAS_MSG_VALUE)
                revert(0x0, 0x4)
            }

            let ptr := mload(0x40)
            // Switch case for different permit lengths, indicating different permit standards
            switch permit.length
            // Compact IERC20Permit
            case 100 {
                mstore(ptr, ERC20_PERMIT)     // store selector
                mstore(add(ptr, 0x04), caller())    // store owner
                mstore(add(ptr, 0x24), address())   // store spender

                // Compact IERC20Permit.permit(uint256 value, uint32 deadline, uint256 r, uint256 vs)
                {  // stack too deep
                    let deadline := shr(224, calldataload(add(permit.offset, 0x20))) // loads permit.offset 0x20..0x23
                    let vs := calldataload(add(permit.offset, 0x44))                 // loads permit.offset 0x44..0x63

                    calldatacopy(add(ptr, 0x44), permit.offset, 0x20)            // store value     = copy permit.offset 0x00..0x19
                    mstore(add(ptr, 0x64), sub(deadline, 1))                     // store deadline  = deadline - 1
                    mstore(add(ptr, 0x84), add(27, shr(255, vs)))                // store v         = most significant bit of vs + 27 (27 or 28)
                    calldatacopy(add(ptr, 0xa4), add(permit.offset, 0x24), 0x20) // store r         = copy permit.offset 0x24..0x43
                    mstore(add(ptr, 0xc4), shr(1, shl(1, vs)))                   // store s         = vs without most significant bit
                }
                // IERC20Permit.permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
                let success := call(gas(), token, 0, ptr, 0xe4, 0, 0)
                if iszero(success) {
                    returndatacopy(ptr, 0x0, returndatasize())
                    revert(ptr, returndatasize())
                }
                ////////////////////////////////////////////////////
                // transferFrom on token
                ////////////////////////////////////////////////////
                // selector for transferFrom(address,address,uint256)
                mstore(ptr, ERC20_TRANSFER_FROM)
                mstore(add(ptr, 0x04), caller())    // store owner
                // spender still in place
                mstore(add(ptr, 0x44), amount)      // store amount (we do not want to take the same as the permit one)

                success := call(gas(), token, 0x0, ptr, 0x64, ptr, 32)

                let rdsize := returndatasize()

                // Check for ERC20 success. ERC20 tokens should return a boolean,
                // but some don't. We accept 0-length return data as success, or at
                // least 32 bytes that starts with a 32-byte boolean true.
                success := and(
                    success, // call itself succeeded
                    or(
                        iszero(rdsize), // no return data, or
                        and(
                            iszero(lt(rdsize, 32)), // at least 32 bytes
                            eq(mload(ptr), 1) // starts with uint256(1)
                        )
                    )
                )

                if iszero(success) {
                    returndatacopy(ptr, 0x0, rdsize)
                    revert(ptr, rdsize)
                }
            }
            // Compact IDaiLikePermit
            case 72 {
                mstore(ptr, DAI_PERMIT)  // store selector
                mstore(add(ptr, 0x04), caller())    // store owner
                mstore(add(ptr, 0x24), address())   // store spender

                // Compact IDaiLikePermit.permit(uint32 nonce, uint32 expiry, uint256 r, uint256 vs)
                {  // stack too deep
                    let expiry := shr(224, calldataload(add(permit.offset, 0x04))) // loads permit.offset 0x04..0x07
                    let vs := calldataload(add(permit.offset, 0x28))               // loads permit.offset 0x28..0x47

                    mstore(add(ptr, 0x44), shr(224, calldataload(permit.offset))) // store nonce   = copy permit.offset 0x00..0x03
                    mstore(add(ptr, 0x64), sub(expiry, 1))                        // store expiry  = expiry - 1
                    mstore(add(ptr, 0x84), true)                                  // store allowed = true
                    mstore(add(ptr, 0xa4), add(27, shr(255, vs)))                 // store v       = most significant bit of vs + 27 (27 or 28)
                    calldatacopy(add(ptr, 0xc4), add(permit.offset, 0x08), 0x20)  // store r       = copy permit.offset 0x08..0x27
                    mstore(add(ptr, 0xe4), shr(1, shl(1, vs)))                    // store s       = vs without most significant bit
                }
                // IDaiLikePermit.permit(address holder, address spender, uint256 nonce, uint256 expiry, bool allowed, uint8 v, bytes32 r, bytes32 s)
                let success := call(gas(), token, 0, ptr, 0x104, 0, 0)
                if iszero(success) {
                    returndatacopy(ptr, 0x0, returndatasize())
                    revert(ptr, returndatasize())
                }
                ////////////////////////////////////////////////////
                // transferFrom on token
                ////////////////////////////////////////////////////
                // selector for transferFrom(address,address,uint256)
                mstore(ptr, ERC20_TRANSFER_FROM)
                mstore(add(ptr, 0x04), caller())    // store owner
                // spender still in place
                mstore(add(ptr, 0x44), amount)      // store amount

                success := call(gas(), token, 0x0, ptr, 0x64, ptr, 32)

                let rdsize := returndatasize()

                // Check for ERC20 success. ERC20 tokens should return a boolean,
                // but some don't. We accept 0-length return data as success, or at
                // least 32 bytes that starts with a 32-byte boolean true.
                success := and(
                    success, // call itself succeeded
                    or(
                        iszero(rdsize), // no return data, or
                        and(
                            iszero(lt(rdsize, 32)), // at least 32 bytes
                            eq(mload(ptr), 1) // starts with uint256(1)
                        )
                    )
                )

                if iszero(success) {
                    returndatacopy(ptr, 0x0, rdsize)
                    revert(ptr, rdsize)
                }
            }
            // IERC20Permit
            case 224 {
                mstore(ptr, ERC20_PERMIT)
                calldatacopy(add(ptr, 0x04), permit.offset, permit.length) // copy permit calldata
                // IERC20Permit.permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
                let success := call(gas(), token, 0, ptr, 0xe4, 0, 0)
                if iszero(success) {
                    returndatacopy(ptr, 0x0, returndatasize())
                    revert(ptr, returndatasize())
                }
                ////////////////////////////////////////////////////
                // transferFrom on token
                ////////////////////////////////////////////////////
                // selector for transferFrom(address,address,uint256)
                mstore(ptr, ERC20_TRANSFER_FROM)
                mstore(add(ptr, 0x04), caller())    // store owner
                // spender still in place
                mstore(add(ptr, 0x44), amount)      // store amount (we do not want to take the same as the permit one)

                success := call(gas(), token, 0x0, ptr, 0x64, ptr, 32)

                let rdsize := returndatasize()

                // Check for ERC20 success. ERC20 tokens should return a boolean,
                // but some don't. We accept 0-length return data as success, or at
                // least 32 bytes that starts with a 32-byte boolean true.
                success := and(
                    success, // call itself succeeded
                    or(
                        iszero(rdsize), // no return data, or
                        and(
                            iszero(lt(rdsize, 32)), // at least 32 bytes
                            eq(mload(ptr), 1) // starts with uint256(1)
                        )
                    )
                )

                if iszero(success) {
                    returndatacopy(ptr, 0x0, rdsize)
                    revert(ptr, rdsize)
                }
            }
            // IDaiLikePermit
            case 256 {
                mstore(ptr, DAI_PERMIT)
                calldatacopy(add(ptr, 0x04), permit.offset, permit.length) // copy permit calldata
                // IDaiLikePermit.permit(address holder, address spender, uint256 nonce, uint256 expiry, bool allowed, uint8 v, bytes32 r, bytes32 s)
                let success := call(gas(), token, 0, ptr, 0x104, 0, 0)
                if iszero(success) {
                    returndatacopy(ptr, 0x0, returndatasize())
                    revert(ptr, returndatasize())
                }
                ////////////////////////////////////////////////////
                // transferFrom on token
                ////////////////////////////////////////////////////
                // selector for transferFrom(address,address,uint256)
                mstore(ptr, ERC20_TRANSFER_FROM)
                mstore(add(ptr, 0x04), caller())    // store owner
                // spender still in place
                mstore(add(ptr, 0x44), amount)

                success := call(gas(), token, 0x0, ptr, 0x64, ptr, 32)

                let rdsize := returndatasize()

                // Check for ERC20 success. ERC20 tokens should return a boolean,
                // but some don't. We accept 0-length return data as success, or at
                // least 32 bytes that starts with a 32-byte boolean true.
                success := and(
                    success, // call itself succeeded
                    or(
                        iszero(rdsize), // no return data, or
                        and(
                            iszero(lt(rdsize, 32)), // at least 32 bytes
                            eq(mload(ptr), 1) // starts with uint256(1)
                        )
                    )
                )

                if iszero(success) {
                    returndatacopy(ptr, 0x0, rdsize)
                    revert(ptr, rdsize)
                }
            }
            // Compact IPermit2
            case 96 {
                // Compact IPermit2.permit(uint160 amount, uint32 expiration, uint32 nonce, uint32 sigDeadline, uint256 r, uint256 vs)
                mstore(ptr, PERMIT2_PERMIT)  // store selector
                mstore(add(ptr, 0x04), caller()) // store owner
                mstore(add(ptr, 0x24), token) // store token

                calldatacopy(add(ptr, 0x50), permit.offset, 0x14)             // store amount = copy permit.offset 0x00..0x13
                // and(0xffffffffffff, ...) - conversion to uint48
                mstore(add(ptr, 0x64), and(0xffffffffffff, sub(shr(224, calldataload(add(permit.offset, 0x14))), 1))) // store expiration = ((permit.offset 0x14..0x17 - 1) & 0xffffffffffff)
                mstore(add(ptr, 0x84), shr(224, calldataload(add(permit.offset, 0x18)))) // store nonce = copy permit.offset 0x18..0x1b
                mstore(add(ptr, 0xa4), address())                               // store spender
                // and(0xffffffffffff, ...) - conversion to uint48
                mstore(add(ptr, 0xc4), and(0xffffffffffff, sub(shr(224, calldataload(add(permit.offset, 0x1c))), 1))) // store sigDeadline = ((permit.offset 0x1c..0x1f - 1) & 0xffffffffffff)
                mstore(add(ptr, 0xe4), 0x100)                                 // store offset = 256
                mstore(add(ptr, 0x104), 0x40)                                 // store length = 64
                calldatacopy(add(ptr, 0x124), add(permit.offset, 0x20), 0x20) // store r      = copy permit.offset 0x20..0x3f
                calldatacopy(add(ptr, 0x144), add(permit.offset, 0x40), 0x20) // store vs     = copy permit.offset 0x40..0x5f
                // IPermit2.permit(address owner, PermitSingle calldata permitSingle, bytes calldata signature)
                if iszero(call(gas(), PERMIT2, 0, ptr, 0x164, 0, 0)) {
                    returndatacopy(0, 0, returndatasize())
                    revert(0, returndatasize())
                }
                ////////////////////////////////////////////////////
                // transferFrom through permit2
                ////////////////////////////////////////////////////
                mstore(ptr, PERMIT2_TRANSFER_FROM)
                mstore(add(ptr, 0x04), caller())
                mstore(add(ptr, 0x24), address())
                mstore(add(ptr, 0x44), amount)
                mstore(add(ptr, 0x64), token)
                if iszero(call(gas(), PERMIT2, 0, ptr, 0x84, 0x0, 0x0)) {
                    returndatacopy(0, 0, returndatasize())
                    revert(0, returndatasize())
                }
            }
            // IPermit2
            case 352 {
                mstore(ptr, PERMIT2_PERMIT)
                calldatacopy(add(ptr, 0x04), permit.offset, permit.length) // copy permit calldata
                // IPermit2.permit(address owner, PermitSingle calldata permitSingle, bytes calldata signature)
                if iszero(call(gas(), PERMIT2, 0, ptr, 0x164, 0, 0)) {
                    returndatacopy(0, 0, returndatasize())
                    revert(0, returndatasize())
                }
                ////////////////////////////////////////////////////
                // transferFrom through permit2
                ////////////////////////////////////////////////////
                mstore(ptr, PERMIT2_TRANSFER_FROM)
                mstore(add(ptr, 0x04), caller())
                mstore(add(ptr, 0x24), address())
                mstore(add(ptr, 0x44), amount)
                mstore(add(ptr, 0x64), token)
                if iszero(call(gas(), PERMIT2, 0, ptr, 0x84, 0x0, 0x0)) {
                    returndatacopy(0, 0, returndatasize())
                    revert(0, returndatasize())
                }
            }
            // Just transfer
            case 0 {
                // selector for transferFrom(address,address,uint256)
                mstore(ptr, ERC20_TRANSFER_FROM)
                mstore(add(ptr, 0x04), caller())
                mstore(add(ptr, 0x24), address())
                mstore(add(ptr, 0x44), amount)

                let success := call(gas(), token, 0x0, ptr, 0x64, ptr, 32)

                let rdsize := returndatasize()

                // Check for ERC20 success. ERC20 tokens should return a boolean,
                // but some don't. We accept 0-length return data as success, or at
                // least 32 bytes that starts with a 32-byte boolean true.
                success := and(
                    success, // call itself succeeded
                    or(
                        iszero(rdsize), // no return data, or
                        and(
                            iszero(lt(rdsize, 32)), // at least 32 bytes
                            eq(mload(ptr), 1) // starts with uint256(1)
                        )
                    )
                )

                if iszero(success) {
                    returndatacopy(ptr, 0x0, rdsize)
                    revert(ptr, rdsize)
                } 
            }
            // Unknown
            default {
                mstore(ptr, _PERMIT_LENGTH_ERROR)
                revert(ptr, 4)
            }
        }
    }
}

File 4 of 4 : ERC20Selectors.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity 0.8.28;

abstract contract ERC20Selectors {
    ////////////////////////////////////////////////////
    // ERC20 selectors
    ////////////////////////////////////////////////////

    /// @dev selector for approve(address,uint256)
    bytes32 internal constant ERC20_APPROVE = 0x095ea7b300000000000000000000000000000000000000000000000000000000;

    /// @dev selector for transferFrom(address,address,uint256)
    bytes32 internal constant ERC20_TRANSFER_FROM = 0x23b872dd00000000000000000000000000000000000000000000000000000000;

    /// @dev selector for transfer(address,uint256)
    bytes32 internal constant ERC20_TRANSFER = 0xa9059cbb00000000000000000000000000000000000000000000000000000000;

    /// @dev selector for allowance(address,address)
    bytes32 internal constant ERC20_ALLOWANCE = 0xdd62ed3e00000000000000000000000000000000000000000000000000000000;

    /// @dev selector for balanceOf(address)
    bytes32 internal constant ERC20_BALANCE_OF = 0x70a0823100000000000000000000000000000000000000000000000000000000;
}

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

Contract Security Audit

Contract ABI

API
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"HasMsgValue","type":"error"},{"inputs":[],"name":"HasNoMsgValue","type":"error"},{"inputs":[],"name":"InvalidSwapCall","type":"error"},{"inputs":[],"name":"NativeTransferFailed","type":"error"},{"inputs":[],"name":"SafePermitBadLength","type":"error"},{"inputs":[{"internalType":"uint256","name":"amountPaid","type":"uint256"},{"internalType":"uint256","name":"amountReceived","type":"uint256"},{"internalType":"bytes","name":"errorData","type":"bytes"}],"name":"SimulationResults","type":"error"},{"inputs":[{"internalType":"bytes","name":"permitData","type":"bytes"},{"internalType":"bytes","name":"swapData","type":"bytes"},{"internalType":"bytes32","name":"assetInData","type":"bytes32"},{"internalType":"bytes32","name":"assetOutData","type":"bytes32"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"address","name":"approvalTarget","type":"address"},{"internalType":"address","name":"swapTarget","type":"address"},{"internalType":"address","name":"receiver","type":"address"}],"name":"simSwapMeta","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"permitData","type":"bytes"},{"internalType":"bytes","name":"swapData","type":"bytes"},{"internalType":"bytes32","name":"assetInData","type":"bytes32"},{"internalType":"bytes32","name":"assetOutData","type":"bytes32"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"address","name":"approvalTarget","type":"address"},{"internalType":"address","name":"swapTarget","type":"address"},{"internalType":"address","name":"receiver","type":"address"}],"name":"swapMeta","outputs":[],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]

6080604052348015600e575f5ffd5b50610f448061001c5f395ff3fe60806040526004361061002b575f3560e01c806384475995146100365780639239fd171461004b575f5ffd5b3661003257005b5f5ffd5b610049610044366004610cbe565b61005e565b005b610049610059366004610cbe565b6102a5565b604080516080810182525f918101829052606081019190915273ffffffffffffffffffffffffffffffffffffffff87811682528616602082018190526100a49083610340565b604082015280516100b59033610340565b8160600181815250505f5f3073ffffffffffffffffffffffffffffffffffffffff16639239fd1760e01b8e8e8e8e8e8e8e8e8e8e6040516024016101029a99989796959493929190610dc0565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090941693909317909252905161018b9190610e57565b5f60405180830381855af49150503d805f81146101c3576040519150601f19603f3d011682016040523d82523d5f602084013e6101c8565b606091505b509150915081610213575f5f826040517f8f7730bd00000000000000000000000000000000000000000000000000000000815260040161020a93929190610e72565b60405180910390fd5b50508060400151610228826020015184610340565b6102329190610ed0565b604082015280516102439033610340565b81606001516102529190610ed0565b606082810182905260408084015190517f8f7730bd0000000000000000000000000000000000000000000000000000000081526004810193909352602483015260448201525f606482015260840161020a565b73ffffffffffffffffffffffffffffffffffffffff86167f800000000000000000000000000000000000000000000000000000000000000087168115610300576102f182878e8e610398565b6102fb828661083e565b610308565b610308610937565b6103138a8a86610966565b61031e8a8a86610a1d565b6103288183610a3e565b6103328784610b27565b505050505050505050505050565b5f82156001811461038c577f70a08231000000000000000000000000000000000000000000000000000000005f528260045260205f60245f875afa610383575f5ffd5b5f519150610391565b823191505b5092915050565b34156103c6577ff6a73902000000000000000000000000000000000000000000000000000000005f5260045ffd5b604051816064811461042a576048811461052e5760e081146105da57610100811461061a576060811461065b5761016081146107855780156107d4577f68275857000000000000000000000000000000000000000000000000000000008252600482fd5b7fd505accf000000000000000000000000000000000000000000000000000000008252336004830152306024830152602084013560e01c604485013560208660448601376001820360648501528060ff1c601b01608485015260206024870160a48601377f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1660c4840152505f8060e484828a5af1806104cc573d5f843e3d83fd5b7f23b872dd0000000000000000000000000000000000000000000000000000000083523360048401528560448401526020836064855f8b5af190503d6001845114602082101516811517821691508161052757805f853e8084fd5b5050610836565b7f8fcbaf0c000000000000000000000000000000000000000000000000000000008252336004830152306024830152600484013560e01c6028850135853560e01c6044850152600182036064850152600160848501528060ff1c601b0160a485015260206008870160c48601377f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1660e4840152505f8061010484828a5af1806104cc573d5f843e3d83fd5b7fd505accf000000000000000000000000000000000000000000000000000000008252828460048401375f5f60e4845f8a5af1806104cc573d5f843e3d83fd5b7f8fcbaf0c000000000000000000000000000000000000000000000000000000008252828460048401375f5f610104845f8a5af1806104cc573d5f843e3d83fd5b7f2b67b57000000000000000000000000000000000000000000000000000000000825233600483015285602483015260148460508401376001601485013560e01c0365ffffffffffff166064830152601884013560e01c60848301523060a48301526001601c85013560e01c0365ffffffffffff1660c483015261010060e4830152604061010483015260208085016101248401376020604085016101448401375f5f610164845f6e22d473030f116ddee9f6b43ac78ba35af1610721573d5f5f3e3d5ffd5b7f36c785160000000000000000000000000000000000000000000000000000000082523360048301523060248301528460448301528560648301525f5f6084845f6e22d473030f116ddee9f6b43ac78ba35af1610780573d5f5f3e3d5ffd5b610836565b7f2b67b570000000000000000000000000000000000000000000000000000000008252828460048401375f5f610164845f6e22d473030f116ddee9f6b43ac78ba35af1610721573d5f5f3e3d5ffd5b7f23b872dd0000000000000000000000000000000000000000000000000000000082523360048301523060248301528460448301526020826064845f8a5af13d6001845114602082101516811517821691508161083357805f853e8084fd5b50505b505050505050565b73ffffffffffffffffffffffffffffffffffffffff8083165f908152602081815260408083209385168352929052205460ff16610933576040517f095ea7b30000000000000000000000000000000000000000000000000000000081528160048201527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60248201526020816044835f875af16108d9575f5ffd5b5073ffffffffffffffffffffffffffffffffffffffff8083165f9081526020818152604080832093851683529290522080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555b5050565b34610964577f07270ad5000000000000000000000000000000000000000000000000000000005f5260045ffd5b565b82357fffffffff00000000000000000000000000000000000000000000000000000000167f23b872dd0000000000000000000000000000000000000000000000000000000081036109d9577fee68db59000000000000000000000000000000000000000000000000000000005f5260045ffd5b506e22d473030f116ddee9f6b43ac78ba38103610a18577fee68db59000000000000000000000000000000000000000000000000000000005f5260045ffd5b505050565b604051828482375f5f848334865af1610a38573d5f5f3e3d5ffd5b50505050565b811561093357801560018114610aec577f70a08231000000000000000000000000000000000000000000000000000000005f523060045260205f60245f855afa505f518015610a38576040517fa9059cbb0000000000000000000000000000000000000000000000000000000081523360048201528160248201526020816044835f885af13d60018351146020821015168115178216915081610ae357805f843e8083fd5b50505050505050565b478015610a38575f5f5f5f84335af1610a38577ff4b3b1bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b817f80000000000000000000000000000000000000000000000000000000000000001615610933578173ffffffffffffffffffffffffffffffffffffffff16801560018114610c0f577f70a08231000000000000000000000000000000000000000000000000000000005f523060045260205f60245f855afa505f518015610c09576040517fa9059cbb0000000000000000000000000000000000000000000000000000000081528460048201528160248201526020816044835f885af13d60018351146020821015168115178216915081610c0557805f843e8083fd5b5050505b50610a38565b478015610c4a575f5f5f5f84885af1610c4a577ff4b3b1bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b5050505050565b5f5f83601f840112610c61575f5ffd5b50813567ffffffffffffffff811115610c78575f5ffd5b602083019150836020828501011115610c8f575f5ffd5b9250929050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610cb9575f5ffd5b919050565b5f5f5f5f5f5f5f5f5f5f6101008b8d031215610cd8575f5ffd5b8a3567ffffffffffffffff811115610cee575f5ffd5b610cfa8d828e01610c51565b909b5099505060208b013567ffffffffffffffff811115610d19575f5ffd5b610d258d828e01610c51565b90995097505060408b0135955060608b0135945060808b01359350610d4c60a08c01610c96565b9250610d5a60c08c01610c96565b9150610d6860e08c01610c96565b90509295989b9194979a5092959850565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b61010081525f610dd561010083018c8e610d79565b8281036020840152610de8818b8d610d79565b604084019990995250506060810195909552608085019390935273ffffffffffffffffffffffffffffffffffffffff91821660a0850152811660c08401521660e090910152949350505050565b5f5b83811015610e4f578181015183820152602001610e37565b50505f910152565b5f8251610e68818460208701610e35565b9190910192915050565b838152826020820152606060408201525f8251806060840152610e9c816080850160208701610e35565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01691909101608001949350505050565b81810381811115610f08577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b9291505056fea2646970667358221220a389e51fb7990b0abd9f93faae7cc346d4ec30a7315ae5f2a6fb836b8688e2f964736f6c634300081c0033

Deployed Bytecode

0x60806040526004361061002b575f3560e01c806384475995146100365780639239fd171461004b575f5ffd5b3661003257005b5f5ffd5b610049610044366004610cbe565b61005e565b005b610049610059366004610cbe565b6102a5565b604080516080810182525f918101829052606081019190915273ffffffffffffffffffffffffffffffffffffffff87811682528616602082018190526100a49083610340565b604082015280516100b59033610340565b8160600181815250505f5f3073ffffffffffffffffffffffffffffffffffffffff16639239fd1760e01b8e8e8e8e8e8e8e8e8e8e6040516024016101029a99989796959493929190610dc0565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090941693909317909252905161018b9190610e57565b5f60405180830381855af49150503d805f81146101c3576040519150601f19603f3d011682016040523d82523d5f602084013e6101c8565b606091505b509150915081610213575f5f826040517f8f7730bd00000000000000000000000000000000000000000000000000000000815260040161020a93929190610e72565b60405180910390fd5b50508060400151610228826020015184610340565b6102329190610ed0565b604082015280516102439033610340565b81606001516102529190610ed0565b606082810182905260408084015190517f8f7730bd0000000000000000000000000000000000000000000000000000000081526004810193909352602483015260448201525f606482015260840161020a565b73ffffffffffffffffffffffffffffffffffffffff86167f800000000000000000000000000000000000000000000000000000000000000087168115610300576102f182878e8e610398565b6102fb828661083e565b610308565b610308610937565b6103138a8a86610966565b61031e8a8a86610a1d565b6103288183610a3e565b6103328784610b27565b505050505050505050505050565b5f82156001811461038c577f70a08231000000000000000000000000000000000000000000000000000000005f528260045260205f60245f875afa610383575f5ffd5b5f519150610391565b823191505b5092915050565b34156103c6577ff6a73902000000000000000000000000000000000000000000000000000000005f5260045ffd5b604051816064811461042a576048811461052e5760e081146105da57610100811461061a576060811461065b5761016081146107855780156107d4577f68275857000000000000000000000000000000000000000000000000000000008252600482fd5b7fd505accf000000000000000000000000000000000000000000000000000000008252336004830152306024830152602084013560e01c604485013560208660448601376001820360648501528060ff1c601b01608485015260206024870160a48601377f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1660c4840152505f8060e484828a5af1806104cc573d5f843e3d83fd5b7f23b872dd0000000000000000000000000000000000000000000000000000000083523360048401528560448401526020836064855f8b5af190503d6001845114602082101516811517821691508161052757805f853e8084fd5b5050610836565b7f8fcbaf0c000000000000000000000000000000000000000000000000000000008252336004830152306024830152600484013560e01c6028850135853560e01c6044850152600182036064850152600160848501528060ff1c601b0160a485015260206008870160c48601377f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1660e4840152505f8061010484828a5af1806104cc573d5f843e3d83fd5b7fd505accf000000000000000000000000000000000000000000000000000000008252828460048401375f5f60e4845f8a5af1806104cc573d5f843e3d83fd5b7f8fcbaf0c000000000000000000000000000000000000000000000000000000008252828460048401375f5f610104845f8a5af1806104cc573d5f843e3d83fd5b7f2b67b57000000000000000000000000000000000000000000000000000000000825233600483015285602483015260148460508401376001601485013560e01c0365ffffffffffff166064830152601884013560e01c60848301523060a48301526001601c85013560e01c0365ffffffffffff1660c483015261010060e4830152604061010483015260208085016101248401376020604085016101448401375f5f610164845f6e22d473030f116ddee9f6b43ac78ba35af1610721573d5f5f3e3d5ffd5b7f36c785160000000000000000000000000000000000000000000000000000000082523360048301523060248301528460448301528560648301525f5f6084845f6e22d473030f116ddee9f6b43ac78ba35af1610780573d5f5f3e3d5ffd5b610836565b7f2b67b570000000000000000000000000000000000000000000000000000000008252828460048401375f5f610164845f6e22d473030f116ddee9f6b43ac78ba35af1610721573d5f5f3e3d5ffd5b7f23b872dd0000000000000000000000000000000000000000000000000000000082523360048301523060248301528460448301526020826064845f8a5af13d6001845114602082101516811517821691508161083357805f853e8084fd5b50505b505050505050565b73ffffffffffffffffffffffffffffffffffffffff8083165f908152602081815260408083209385168352929052205460ff16610933576040517f095ea7b30000000000000000000000000000000000000000000000000000000081528160048201527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60248201526020816044835f875af16108d9575f5ffd5b5073ffffffffffffffffffffffffffffffffffffffff8083165f9081526020818152604080832093851683529290522080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555b5050565b34610964577f07270ad5000000000000000000000000000000000000000000000000000000005f5260045ffd5b565b82357fffffffff00000000000000000000000000000000000000000000000000000000167f23b872dd0000000000000000000000000000000000000000000000000000000081036109d9577fee68db59000000000000000000000000000000000000000000000000000000005f5260045ffd5b506e22d473030f116ddee9f6b43ac78ba38103610a18577fee68db59000000000000000000000000000000000000000000000000000000005f5260045ffd5b505050565b604051828482375f5f848334865af1610a38573d5f5f3e3d5ffd5b50505050565b811561093357801560018114610aec577f70a08231000000000000000000000000000000000000000000000000000000005f523060045260205f60245f855afa505f518015610a38576040517fa9059cbb0000000000000000000000000000000000000000000000000000000081523360048201528160248201526020816044835f885af13d60018351146020821015168115178216915081610ae357805f843e8083fd5b50505050505050565b478015610a38575f5f5f5f84335af1610a38577ff4b3b1bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b817f80000000000000000000000000000000000000000000000000000000000000001615610933578173ffffffffffffffffffffffffffffffffffffffff16801560018114610c0f577f70a08231000000000000000000000000000000000000000000000000000000005f523060045260205f60245f855afa505f518015610c09576040517fa9059cbb0000000000000000000000000000000000000000000000000000000081528460048201528160248201526020816044835f885af13d60018351146020821015168115178216915081610c0557805f843e8083fd5b5050505b50610a38565b478015610c4a575f5f5f5f84885af1610c4a577ff4b3b1bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b5050505050565b5f5f83601f840112610c61575f5ffd5b50813567ffffffffffffffff811115610c78575f5ffd5b602083019150836020828501011115610c8f575f5ffd5b9250929050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610cb9575f5ffd5b919050565b5f5f5f5f5f5f5f5f5f5f6101008b8d031215610cd8575f5ffd5b8a3567ffffffffffffffff811115610cee575f5ffd5b610cfa8d828e01610c51565b909b5099505060208b013567ffffffffffffffff811115610d19575f5ffd5b610d258d828e01610c51565b90995097505060408b0135955060608b0135945060808b01359350610d4c60a08c01610c96565b9250610d5a60c08c01610c96565b9150610d6860e08c01610c96565b90509295989b9194979a5092959850565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b61010081525f610dd561010083018c8e610d79565b8281036020840152610de8818b8d610d79565b604084019990995250506060810195909552608085019390935273ffffffffffffffffffffffffffffffffffffffff91821660a0850152811660c08401521660e090910152949350505050565b5f5b83811015610e4f578181015183820152602001610e37565b50505f910152565b5f8251610e68818460208701610e35565b9190910192915050565b838152826020820152606060408201525f8251806060840152610e9c816080850160208701610e35565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01691909101608001949350505050565b81810381811115610f08577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b9291505056fea2646970667358221220a389e51fb7990b0abd9f93faae7cc346d4ec30a7315ae5f2a6fb836b8688e2f964736f6c634300081c0033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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