ETH Price: $2,496.07 (-2.96%)

Contract

0x1E00000000Cf8ba83e0005c59c1Bf1C4682C8E00
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Command203900292024-07-26 10:08:3599 days ago1721988515IN
Intents Engine V1
0 ETH0.000440863.00733419
Command202889022024-07-12 7:22:47113 days ago1720768967IN
Intents Engine V1
0 ETH0.001349629.34067736
Command202704872024-07-09 17:40:23115 days ago1720546823IN
Intents Engine V1
0 ETH0.000532934.91024533
Command202040232024-06-30 10:51:47125 days ago1719744707IN
Intents Engine V1
0.001 ETH0.000323282.58595243
Command201830882024-06-27 12:40:59128 days ago1719492059IN
Intents Engine V1
0 ETH0.000919036.19948916
Command201830832024-06-27 12:39:59128 days ago1719491999IN
Intents Engine V1
0 ETH0.000804036.10670987
Command201782182024-06-26 20:22:47128 days ago1719433367IN
Intents Engine V1
0.00333 ETH0.001256319.90577071
Command201781992024-06-26 20:18:59128 days ago1719433139IN
Intents Engine V1
0.00333 ETH0.00141859.8559969
Command201198012024-06-18 16:22:23136 days ago1718727743IN
Intents Engine V1
0.00777 ETH0.001276189.18295815
Command200242922024-06-05 7:59:59150 days ago1717574399IN
Intents Engine V1
0.001 ETH0.0008142510.7550105
Command192713852024-02-20 20:47:23255 days ago1708462043IN
Intents Engine V1
0 ETH0.0059992841.59355651
Command192687532024-02-20 11:55:11256 days ago1708430111IN
Intents Engine V1
0 ETH0.0044591230.98272159
Command192683642024-02-20 10:36:35256 days ago1708425395IN
Intents Engine V1
0 ETH0.0044469930.59382329
Send192528052024-02-18 6:06:35258 days ago1708236395IN
Intents Engine V1
0.001002 ETH0.0012194116.49041193
Command192422322024-02-16 18:27:35259 days ago1708108055IN
Intents Engine V1
0.001 ETH0.0028240531.82174209
Command192421222024-02-16 18:05:35259 days ago1708106735IN
Intents Engine V1
0.001 ETH0.0040344344.90836899
Command192410452024-02-16 14:28:11259 days ago1708093691IN
Intents Engine V1
0 ETH0.00530143.05661215
Command192389212024-02-16 7:16:35260 days ago1708067795IN
Intents Engine V1
0.01 ETH0.0028682125.37258584

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To
203900292024-07-26 10:08:3599 days ago1721988515
Intents Engine V1
0.01282379 ETH
203900292024-07-26 10:08:3599 days ago1721988515
Intents Engine V1
0.01282379 ETH
202889022024-07-12 7:22:47113 days ago1720768967
Intents Engine V1
0.00645518 ETH
202889022024-07-12 7:22:47113 days ago1720768967
Intents Engine V1
0.00645518 ETH
202040232024-06-30 10:51:47125 days ago1719744707
Intents Engine V1
0.001 ETH
201830882024-06-27 12:40:59128 days ago1719492059
Intents Engine V1
0.03189631 ETH
201830882024-06-27 12:40:59128 days ago1719492059
Intents Engine V1
0.03189631 ETH
201830832024-06-27 12:39:59128 days ago1719491999
Intents Engine V1
0.00732854 ETH
201830832024-06-27 12:39:59128 days ago1719491999
Intents Engine V1
0.00732854 ETH
201782182024-06-26 20:22:47128 days ago1719433367
Intents Engine V1
0.00333 ETH
201781992024-06-26 20:18:59128 days ago1719433139
Intents Engine V1
0.00333 ETH
201198012024-06-18 16:22:23136 days ago1718727743
Intents Engine V1
0.00777 ETH
200242922024-06-05 7:59:59150 days ago1717574399
Intents Engine V1
0.001 ETH
192687532024-02-20 11:55:11256 days ago1708430111
Intents Engine V1
0.00340178 ETH
192687532024-02-20 11:55:11256 days ago1708430111
Intents Engine V1
0.00340178 ETH
192683642024-02-20 10:36:35256 days ago1708425395
Intents Engine V1
0.03695706 ETH
192683642024-02-20 10:36:35256 days ago1708425395
Intents Engine V1
0.03695706 ETH
192528052024-02-18 6:06:35258 days ago1708236395
Intents Engine V1
0.001002 ETH
192422322024-02-16 18:27:35259 days ago1708108055
Intents Engine V1
0.001 ETH
192421222024-02-16 18:05:35259 days ago1708106735
Intents Engine V1
0.001 ETH
192410452024-02-16 14:28:11259 days ago1708093691
Intents Engine V1
0.00708286 ETH
192410452024-02-16 14:28:11259 days ago1708093691
Intents Engine V1
0.00708286 ETH
192400262024-02-16 11:00:47260 days ago1708081247
Intents Engine V1
0.001 ETH
192400262024-02-16 11:00:47260 days ago1708081247
Intents Engine V1
0.001 ETH
192389212024-02-16 7:16:35260 days ago1708067795
Intents Engine V1
0.01 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
IE

Compiler Version
v0.8.24+commit.e11b9ed9

Optimization Enabled:
Yes with 9999999 runs

Other Settings:
shanghai EvmVersion
File 1 of 3 : IE.sol
// ⌘ ⌘ ⌘ ⌘ ⌘ ⌘ ⌘ ⌘ ⌘ ⌘ ⌘ ⌘ ⌘ ⌘ ⌘ ⌘ ⌘ ⌘ ⌘
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.19;

import {SafeTransferLib} from "../lib/solady/src/utils/SafeTransferLib.sol";
import {MetadataReaderLib} from "../lib/solady/src/utils/MetadataReaderLib.sol";

/// @title Intents Engine (IE)
/// @notice Simple helper contract for turning transactional intents into executable code.
/// @dev V1 simulates typical commands (sending and swapping tokens) and includes execution.
/// IE also has a workflow to verify the intent of ERC4337 account userOps against calldata.
/// @author nani.eth (https://github.com/NaniDAO/ie)
/// @custom:version 1.0.0
contract IE {
    /// ======================= LIBRARY USAGE ======================= ///

    /// @dev Metadata reader library.
    using MetadataReaderLib for address;

    /// @dev Safe token transfer library.
    using SafeTransferLib for address;

    /// ======================= CUSTOM ERRORS ======================= ///

    /// @dev Bad math.
    error Overflow();

    /// @dev Caller fails.
    error Unauthorized();

    /// @dev 0-liquidity.
    error InvalidSwap();

    /// @dev Invalid command.
    error InvalidSyntax();

    /// @dev Non-numeric character.
    error InvalidCharacter();

    /// =========================== EVENTS =========================== ///

    /// @dev Logs the registration of a token name.
    event NameSet(address indexed token, string name);

    /// ========================== STRUCTS ========================== ///

    /// @dev The ERC4337 user operation (userOp) struct.
    struct UserOperation {
        address sender;
        uint256 nonce;
        bytes initCode;
        bytes callData;
        uint256 callGasLimit;
        uint256 verificationGasLimit;
        uint256 preVerificationGas;
        uint256 maxFeePerGas;
        uint256 maxPriorityFeePerGas;
        bytes paymasterAndData;
        bytes signature;
    }

    /// @dev The packed ERC4337 user operation (userOp) struct.
    struct PackedUserOperation {
        address sender;
        uint256 nonce;
        bytes initCode;
        bytes callData;
        bytes32 accountGasLimits;
        uint256 preVerificationGas;
        bytes32 gasFees; // `maxPriorityFee` and `maxFeePerGas`.
        bytes paymasterAndData;
        bytes signature;
    }

    /// =========================== ENUMS =========================== ///

    /// @dev `ENSAsciiNormalizer` rules.
    enum Rule {
        DISALLOWED,
        VALID
    }

    /// ========================= CONSTANTS ========================= ///

    /// @dev The governing DAO address.
    address internal constant DAO = 0xDa000000000000d2885F108500803dfBAaB2f2aA;

    /// @dev The NANI token address.
    address internal constant NANI = 0x00000000000025824328358250920B271f348690;

    /// @dev The conventional ERC7528 ETH address.
    address internal constant ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;

    /// @dev The canonical wrapped ETH address.
    address internal constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;

    /// @dev The popular wrapped BTC address.
    address internal constant WBTC = 0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599;

    /// @dev The Circle USD stablecoin address.
    address internal constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;

    /// @dev The Tether USD stablecoin address.
    address internal constant USDT = 0xdAC17F958D2ee523a2206206994597C13D831ec7;

    /// @dev The Maker DAO USD stablecoin address.
    address internal constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F;

    /// @dev ENS fallback registry contract.
    IENSHelper internal constant ENS_REGISTRY =
        IENSHelper(0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e);

    /// @dev ENS name wrapper token contract.
    IENSHelper internal constant ENS_WRAPPER =
        IENSHelper(0xD4416b13d2b3a9aBae7AcD5D6C2BbDBE25686401);

    /// @dev The address of the Uniswap V3 Factory.
    address internal constant UNISWAP_V3_FACTORY = 0x1F98431c8aD98523631AE4a59f267346ea31F984;

    /// @dev The Uniswap V3 Pool `initcodehash`.
    bytes32 internal constant UNISWAP_V3_POOL_INIT_CODE_HASH =
        0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54;

    /// @dev The minimum value that can be returned from `getSqrtRatioAtTick` (plus one).
    uint160 internal constant MIN_SQRT_RATIO_PLUS_ONE = 4295128740;

    /// @dev The maximum value that can be returned from `getSqrtRatioAtTick` (minus one).
    uint160 internal constant MAX_SQRT_RATIO_MINUS_ONE =
        1461446703485210103287273052203988822378723970341;

    /// @dev String mapping for `ENSAsciiNormalizer` logic.
    bytes internal constant ASCII_MAP =
        hex"2d00020101000a010700016101620163016401650166016701680169016a016b016c016d016e016f0170017101720173017401750176017701780179017a06001a010500";

    /// ========================== STORAGE ========================== ///

    /// @dev DAO-governed token address naming.
    mapping(string name => address) public tokens;

    /// @dev Each index in idnamap refers to an ascii code point.
    /// If idnamap[char] > 2, char maps to a valid ascii character.
    /// Otherwise, idna[char] returns Rule.DISALLOWED or Rule.VALID.
    /// Modified from `ENSAsciiNormalizer` deployed by royalfork.eth
    /// (0x4A5cae3EC0b144330cf1a6CeAD187D8F6B891758).
    bytes1[] internal _idnamap;

    /// ======================== CONSTRUCTOR ======================== ///

    /// @dev Constructs this IE with `ASCII_MAP`.
    constructor() payable {
        unchecked {
            for (uint256 i; i != ASCII_MAP.length; i += 2) {
                bytes1 r = ASCII_MAP[i + 1];
                for (uint8 j; j != uint8(ASCII_MAP[i]); ++j) {
                    _idnamap.push(r);
                }
            }
        }
    }

    /// ====================== COMMAND PREVIEW ====================== ///

    /// @notice Preview natural language smart contract command.
    /// The `send` syntax uses ENS naming: 'send vitalik 20 DAI'.
    /// `swap` syntax uses common format: 'swap 100 DAI for WETH'.
    function previewCommand(string calldata intent)
        public
        view
        virtual
        returns (
            address to, // Receiver address.
            uint256 amount, // Formatted amount.
            address token, // Asset to send `to`.
            bytes memory callData, // Raw calldata for send transaction.
            bytes memory executeCallData // Anticipates common execute API.
        )
    {
        string memory normalized = _lowercase(intent);
        bytes32 action = _extraction(normalized);
        if (action == "send" || action == "transfer") {
            (string memory _to, string memory _amount, string memory _token) =
                _extractSend(normalized);
            (to, amount, token, callData, executeCallData) = previewSend(_to, _amount, _token);
        } else if (action == "swap" || action == "exchange") {
            (string memory amountIn, string memory tokenIn, string memory tokenOut) =
                _extractSwap(normalized);
            (amount, token, to) = previewSwap(amountIn, tokenIn, tokenOut);
        } else {
            revert InvalidSyntax(); // Invalid command format.
        }
    }

    /// @dev Previews a `send` command from the parts of a matched intent string.
    function previewSend(string memory to, string memory amount, string memory token)
        public
        view
        virtual
        returns (
            address _to,
            uint256 _amount,
            address _token,
            bytes memory callData,
            bytes memory executeCallData
        )
    {
        _token = _returnTokenConstant(bytes32(bytes(token))); // Check constant.
        if (_token == address(0)) _token = tokens[token]; // Check storage.
        bool isETH = _token == ETH; // Memo whether the token is ETH or not.
        (, _to,) = whatIsTheAddressOf(to); // Fetch receiver address from ENS.
        _amount = _stringToUint(amount, isETH ? 18 : _token.readDecimals());
        if (!isETH) callData = abi.encodeCall(IToken.transfer, (_to, _amount));
        executeCallData =
            abi.encodeCall(IExecutor.execute, (isETH ? _to : _token, isETH ? _amount : 0, callData));
    }

    /// @dev Previews a `swap` command from the parts of a matched intent string.
    function previewSwap(string memory amountIn, string memory tokenIn, string memory tokenOut)
        public
        view
        virtual
        returns (uint256 _amountIn, address _tokenIn, address _tokenOut)
    {
        _tokenIn = _returnTokenConstant(bytes32(bytes(tokenIn)));
        if (_tokenIn == address(0)) _tokenIn = tokens[tokenIn];
        _tokenOut = _returnTokenConstant(bytes32(bytes(tokenOut)));
        if (_tokenOut == address(0)) _tokenOut = tokens[tokenOut];
        _amountIn = _stringToUint(amountIn, _tokenIn == ETH ? 18 : _tokenIn.readDecimals());
    }

    /// @dev Checks ERC4337 userOp against the output of the command intent.
    function checkUserOp(string calldata intent, UserOperation calldata userOp)
        public
        view
        virtual
        returns (bool)
    {
        (,,,, bytes memory executeCallData) = previewCommand(intent);
        if (executeCallData.length != userOp.callData.length) return false;
        return keccak256(executeCallData) == keccak256(userOp.callData);
    }

    /// @dev Checks packed ERC4337 userOp against the output of the command intent.
    function checkPackedUserOp(string calldata intent, PackedUserOperation calldata userOp)
        public
        view
        virtual
        returns (bool)
    {
        (,,,, bytes memory executeCallData) = previewCommand(intent);
        if (executeCallData.length != userOp.callData.length) return false;
        return keccak256(executeCallData) == keccak256(userOp.callData);
    }

    /// @dev Checks and returns the canonical token address constant for a matched intent string.
    function _returnTokenConstant(bytes32 token) internal view virtual returns (address _token) {
        if (token == "eth" || token == "ether") return ETH;
        if (token == "usdc") return USDC;
        if (token == "usdt") return USDT;
        if (token == "dai") return DAI;
        if (token == "nani") return NANI;
        if (token == "weth") return WETH;
        if (token == "wbtc" || token == "btc" || token == "bitcoin") return WBTC;
    }

    /// ===================== COMMAND EXECUTION ===================== ///

    /// @dev Executes a text command from an intent string.
    function command(string calldata intent) public payable virtual {
        string memory normalized = _lowercase(intent);
        bytes32 action = _extraction(normalized);
        if (action == "send" || action == "transfer") {
            (string memory to, string memory amount, string memory token) = _extractSend(normalized);
            send(to, amount, token);
        } else if (action == "swap" || action == "exchange") {
            (string memory amountIn, string memory tokenIn, string memory tokenOut) =
                _extractSwap(normalized);
            swap(amountIn, tokenIn, tokenOut);
        } else {
            revert InvalidSyntax(); // Invalid command format.
        }
    }

    /// @dev Executes a `send` command from the parts of a matched intent string.
    function send(string memory to, string memory amount, string memory token)
        public
        payable
        virtual
    {
        address _token = _returnTokenConstant(bytes32(bytes(token)));
        if (_token == address(0)) _token = tokens[token];
        (, address _to,) = whatIsTheAddressOf(to);
        if (_token == ETH) {
            _to.safeTransferETH(_stringToUint(amount, 18));
        } else {
            _token.safeTransferFrom(msg.sender, _to, _stringToUint(amount, _token.readDecimals()));
        }
    }

    /// @dev Executes a `swap` command from the parts of a matched intent string.
    function swap(string memory amountIn, string memory tokenIn, string memory tokenOut)
        public
        payable
        virtual
    {
        address _tokenIn = _returnTokenConstant(bytes32(bytes(tokenIn)));
        if (_tokenIn == address(0)) _tokenIn = tokens[tokenIn];
        address _tokenOut = _returnTokenConstant(bytes32(bytes(tokenOut)));
        if (_tokenOut == address(0)) _tokenOut = tokens[tokenOut];
        bool ETHIn = _tokenIn == ETH;
        bool ETHOut = _tokenOut == ETH;
        if (ETHIn) _tokenIn = WETH;
        if (ETHOut) _tokenOut = WETH;
        uint256 _amountIn = _stringToUint(amountIn, ETHIn ? 18 : _tokenIn.readDecimals());
        if (_amountIn >= 1 << 255) revert Overflow();
        (address pool, bool zeroForOne) = _computePoolAddress(_tokenIn, _tokenOut);
        ISwapRouter(pool).swap(
            !ETHOut ? msg.sender : address(this),
            zeroForOne,
            int256(_amountIn),
            zeroForOne ? MIN_SQRT_RATIO_PLUS_ONE : MAX_SQRT_RATIO_MINUS_ONE,
            abi.encodePacked(ETHIn, ETHOut, msg.sender, _tokenIn, _tokenOut)
        );
    }

    /// @dev Fallback `uniswapV3SwapCallback`.
    /// If ETH is swapped, WETH is forwarded.
    fallback() external payable virtual {
        int256 amount0Delta;
        int256 amount1Delta;
        bool ETHIn;
        bool ETHOut;
        address payer;
        address tokenIn;
        address tokenOut;
        assembly ("memory-safe") {
            amount0Delta := calldataload(0x4)
            amount1Delta := calldataload(0x24)
            ETHIn := byte(0, calldataload(0x84))
            ETHOut := byte(0, calldataload(add(0x84, 1)))
            payer := shr(96, calldataload(add(0x84, 2)))
            tokenIn := shr(96, calldataload(add(0x84, 22)))
            tokenOut := shr(96, calldataload(add(0x84, 42)))
        }
        if (amount0Delta <= 0 && amount1Delta <= 0) revert InvalidSwap();
        (address pool, bool zeroForOne) = _computePoolAddress(tokenIn, tokenOut);
        if (msg.sender != pool) revert Unauthorized(); // Only pair pool can call.
        if (ETHIn) {
            _wrapETH(uint256(zeroForOne ? amount0Delta : amount1Delta));
        } else {
            tokenIn.safeTransferFrom(
                payer, msg.sender, uint256(zeroForOne ? amount0Delta : amount1Delta)
            );
        }
        if (ETHOut) {
            uint256 amount = uint256(-(zeroForOne ? amount1Delta : amount0Delta));
            _unwrapETH(amount);
            payer.safeTransferETH(amount);
        }
    }

    /// @dev Computes the create2 address for given token pair.
    function _computePoolAddress(address tokenA, address tokenB)
        internal
        view
        virtual
        returns (address pool, bool zeroForOne)
    {
        if (tokenA < tokenB) zeroForOne = true;
        else (tokenA, tokenB) = (tokenB, tokenA);
        pool = _computePairHash(tokenA, tokenB, 3000); // Mid fee.
        if (pool.code.length != 0) return (pool, zeroForOne);
        else pool = _computePairHash(tokenA, tokenB, 500); // Low fee.
        if (pool.code.length != 0) return (pool, zeroForOne);
        else pool = _computePairHash(tokenA, tokenB, 100); // Lowest fee.
        if (pool.code.length != 0) return (pool, zeroForOne);
        else pool = _computePairHash(tokenA, tokenB, 10000); // Highest fee.
        if (pool.code.length != 0) return (pool, zeroForOne);
    }

    /// @dev Computes the create2 deployment hash for given token pair.
    function _computePairHash(address token0, address token1, uint24 fee)
        internal
        pure
        virtual
        returns (address pool)
    {
        bytes32 salt = keccak256(abi.encode(token0, token1, fee));
        assembly ("memory-safe") {
            mstore8(0x00, 0xff) // Write the prefix.
            mstore(0x35, UNISWAP_V3_POOL_INIT_CODE_HASH)
            mstore(0x01, shl(96, UNISWAP_V3_FACTORY))
            mstore(0x15, salt)
            pool := keccak256(0x00, 0x55)
            mstore(0x35, 0) // Restore overwritten.
        }
    }

    /// @dev Wraps an `amount` of ETH to WETH and funds pool caller for swap.
    function _wrapETH(uint256 amount) internal virtual {
        assembly ("memory-safe") {
            pop(call(gas(), WETH, amount, codesize(), 0x00, codesize(), 0x00))
            mstore(0x14, caller()) // Store the `pool` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
            pop(call(gas(), WETH, 0, 0x10, 0x44, codesize(), 0x00))
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Unwraps an `amount` of ETH from WETH for return.
    function _unwrapETH(uint256 amount) internal virtual {
        assembly ("memory-safe") {
            mstore(0x00, 0x2e1a7d4d) // `withdraw(uint256)`.
            mstore(0x20, amount) // Store the `amount` argument.
            pop(call(gas(), WETH, 0, 0x1c, 0x24, codesize(), 0x00))
        }
    }

    /// @dev ETH receiver fallback.
    receive() external payable virtual {
        if (msg.sender != WETH) revert Unauthorized();
    }

    /// ================== BALANCE & SUPPLY HELPERS ================== ///

    /// @dev Returns the balance of a named account in a named token.
    function whatIsTheBalanceOf(string calldata name, /*(bob)*/ /*in*/ string calldata token)
        public
        view
        virtual
        returns (uint256 balance, uint256 balanceAdjusted)
    {
        (, address _name,) = whatIsTheAddressOf(name);
        string memory normalized = _lowercase(token);
        address _token = _returnTokenConstant(bytes32(bytes(normalized)));
        if (_token == address(0)) _token = tokens[token];
        bool isETH = _token == ETH;
        balance = isETH ? _name.balance : _token.balanceOf(_name);
        balanceAdjusted = balance / 10 ** (isETH ? 18 : _token.readDecimals());
    }

    /// @dev Returns the total supply of a named token.
    function whatIsTheTotalSupplyOf(string calldata token)
        public
        view
        virtual
        returns (uint256 supply, uint256 supplyAdjusted)
    {
        address _token = _returnTokenConstant(bytes32(bytes(token)));
        if (_token == address(0)) _token = tokens[token];
        if (_token == ETH) revert InvalidSyntax();
        assembly ("memory-safe") {
            mstore(0x00, 0x18160ddd) // `totalSupply()`.
            if iszero(staticcall(gas(), _token, 0x1c, 0x04, 0x20, 0x20)) {
                revert(codesize(), 0x00)
            }
            supply := mload(0x20)
        }
        supplyAdjusted = supply / 10 ** _token.readDecimals();
    }

    /// ====================== ENS VERIFICATION ====================== ///

    /// @dev Returns ENS name ownership details.
    function whatIsTheAddressOf(string memory name)
        public
        view
        virtual
        returns (address owner, address receiver, bytes32 node)
    {
        node = _namehash(string(abi.encodePacked(name, ".eth")));
        owner = ENS_REGISTRY.owner(node);
        if (IENSHelper(owner) == ENS_WRAPPER) owner = ENS_WRAPPER.ownerOf(uint256(node));
        receiver = IENSHelper(ENS_REGISTRY.resolver(node)).addr(node); // Fails on misname.
    }

    /// @dev Computes an ENS domain namehash.
    function _namehash(string memory domain) internal view virtual returns (bytes32 node) {
        // Process labels (in reverse order for namehash).
        uint256 i = bytes(domain).length;
        uint256 lastDot = i;
        unchecked {
            for (; i != 0; --i) {
                bytes1 c = bytes(domain)[i - 1];
                if (c == ".") {
                    node = keccak256(abi.encodePacked(node, _labelhash(domain, i, lastDot)));
                    lastDot = i - 1;
                    continue;
                }
                require(c < 0x80);
                bytes1 r = _idnamap[uint8(c)];
                require(uint8(r) != uint8(Rule.DISALLOWED));
                if (uint8(r) > 1) {
                    bytes(domain)[i - 1] = r;
                }
            }
        }
        return keccak256(abi.encodePacked(node, _labelhash(domain, i, lastDot)));
    }

    /// @dev Computes an ENS domain labelhash given its start and end.
    function _labelhash(string memory domain, uint256 start, uint256 end)
        internal
        pure
        virtual
        returns (bytes32 hash)
    {
        assembly ("memory-safe") {
            hash := keccak256(add(add(domain, 0x20), start), sub(end, start))
        }
    }

    /// ========================= GOVERNANCE ========================= ///

    /// @dev Sets a public `name` tag for a given `token` address. Governed by DAO.
    function setName(address token, string calldata name) public payable virtual {
        if (msg.sender != DAO) revert Unauthorized();
        string memory normalized = _lowercase(name);
        emit NameSet(tokens[normalized] = token, normalized);
    }

    /// @dev Sets a public name and ticker for a given `token` address.
    function setNameAndTicker(address token) public payable virtual {
        string memory normalizedName = _lowercase(token.readName());
        string memory normalizedSymbol = _lowercase(token.readSymbol());
        emit NameSet(tokens[normalizedName] = token, normalizedName);
        emit NameSet(tokens[normalizedSymbol] = token, normalizedSymbol);
    }

    /// ===================== STRING OPERATIONS ===================== ///

    /// @dev Returns copy of string in lowercase.
    /// Modified from Solady LibString `toCase`.
    function _lowercase(string memory subject)
        internal
        pure
        virtual
        returns (string memory result)
    {
        assembly ("memory-safe") {
            let length := mload(subject)
            if length {
                result := add(mload(0x40), 0x20)
                subject := add(subject, 1)
                let flags := shl(add(70, shl(5, 0)), 0x3ffffff)
                let w := not(0)
                for { let o := length } 1 {} {
                    o := add(o, w)
                    let b := and(0xff, mload(add(subject, o)))
                    mstore8(add(result, o), xor(b, and(shr(b, flags), 0x20)))
                    if iszero(o) { break }
                }
                result := mload(0x40)
                mstore(result, length) // Store the length.
                let last := add(add(result, 0x20), length)
                mstore(last, 0) // Zeroize the slot after the string.
                mstore(0x40, add(last, 0x20)) // Allocate the memory.
            }
        }
    }

    /// @dev Extracts the first word (action) as bytes32.
    function _extraction(string memory normalizedIntent)
        internal
        pure
        virtual
        returns (bytes32 result)
    {
        assembly ("memory-safe") {
            let str := add(normalizedIntent, 0x20)
            for { let i } lt(i, 0x20) { i := add(i, 1) } {
                let char := byte(0, mload(add(str, i)))
                if eq(char, 0x20) { break }
                result := or(result, shl(sub(248, mul(i, 8)), char))
            }
        }
    }

    /// @dev Extract the key words of normalized `send` intent.
    function _extractSend(string memory normalizedIntent)
        internal
        pure
        virtual
        returns (string memory to, string memory amount, string memory token)
    {
        string[] memory parts = _split(normalizedIntent, " ");
        if (parts.length == 4) return (parts[1], parts[2], parts[3]);
        if (parts.length == 5) return (parts[4], parts[1], parts[2]);
        else revert InvalidSyntax(); // Command is not formatted.
    }

    /// @dev Extract the key words of normalized `swap` intent.
    function _extractSwap(string memory normalizedIntent)
        internal
        pure
        virtual
        returns (string memory amountIn, string memory tokenIn, string memory tokenOut)
    {
        string[] memory parts = _split(normalizedIntent, " ");
        if (parts.length == 5) return (parts[1], parts[2], parts[4]);
        else revert InvalidSyntax(); // Command is not formatted.
    }

    /// @dev Split the intent into an array of words.
    function _split(string memory base, bytes1 delimiter)
        internal
        pure
        virtual
        returns (string[] memory parts)
    {
        unchecked {
            bytes memory baseBytes = bytes(base);
            uint256 count = 1;
            for (uint256 i; i != baseBytes.length; ++i) {
                if (baseBytes[i] == delimiter) {
                    ++count;
                }
            }
            parts = new string[](count);
            uint256 partIndex;
            uint256 start;
            for (uint256 i; i <= baseBytes.length; ++i) {
                if (i == baseBytes.length || baseBytes[i] == delimiter) {
                    bytes memory part = new bytes(i - start);
                    for (uint256 j = start; j != i; ++j) {
                        part[j - start] = baseBytes[j];
                    }
                    parts[partIndex] = string(part);
                    ++partIndex;
                    start = i + 1;
                }
            }
        }
    }

    /// @dev Convert string to decimalized numerical value.
    function _stringToUint(string memory s, uint8 decimals)
        internal
        pure
        virtual
        returns (uint256 result)
    {
        unchecked {
            bool hasDecimal;
            uint256 decimalPlaces;
            bytes memory b = bytes(s);
            for (uint256 i; i != b.length; ++i) {
                if (b[i] >= "0" && b[i] <= "9") {
                    result = result * 10 + uint8(b[i]) - 48;
                    if (hasDecimal) {
                        ++decimalPlaces;
                        if (decimalPlaces > decimals) {
                            break;
                        }
                    }
                } else if (b[i] == "." && !hasDecimal) {
                    hasDecimal = true;
                } else {
                    revert InvalidCharacter();
                }
            }
            if (decimalPlaces < decimals) {
                result *= 10 ** (decimals - decimalPlaces);
            }
        }
    }
}

/// @dev ENS name resolution helper contracts interface.
interface IENSHelper {
    function addr(bytes32) external view returns (address);
    function owner(bytes32) external view returns (address);
    function ownerOf(uint256) external view returns (address);
    function resolver(bytes32) external view returns (address);
}

/// @dev Simple token transfer interface.
interface IToken {
    function transfer(address, uint256) external returns (bool);
}

/// @notice Simple calldata executor interface.
interface IExecutor {
    function execute(address, uint256, bytes calldata) external payable returns (bytes memory);
}

/// @dev Simple Uniswap V3 swapping interface.
interface ISwapRouter {
    function swap(address, bool, int256, uint160, bytes calldata)
        external
        returns (int256, int256);
}

File 2 of 3 : SafeTransferLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
///
/// @dev Note:
/// - For ETH transfers, please use `forceSafeTransferETH` for DoS protection.
/// - For ERC20s, this implementation won't check that a token has code,
///   responsibility is delegated to the caller.
library SafeTransferLib {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The ETH transfer has failed.
    error ETHTransferFailed();

    /// @dev The ERC20 `transferFrom` has failed.
    error TransferFromFailed();

    /// @dev The ERC20 `transfer` has failed.
    error TransferFailed();

    /// @dev The ERC20 `approve` has failed.
    error ApproveFailed();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         CONSTANTS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Suggested gas stipend for contract receiving ETH that disallows any storage writes.
    uint256 internal constant GAS_STIPEND_NO_STORAGE_WRITES = 2300;

    /// @dev Suggested gas stipend for contract receiving ETH to perform a few
    /// storage reads and writes, but low enough to prevent griefing.
    uint256 internal constant GAS_STIPEND_NO_GRIEF = 100000;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       ETH OPERATIONS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // If the ETH transfer MUST succeed with a reasonable gas budget, use the force variants.
    //
    // The regular variants:
    // - Forwards all remaining gas to the target.
    // - Reverts if the target reverts.
    // - Reverts if the current contract has insufficient balance.
    //
    // The force variants:
    // - Forwards with an optional gas stipend
    //   (defaults to `GAS_STIPEND_NO_GRIEF`, which is sufficient for most cases).
    // - If the target reverts, or if the gas stipend is exhausted,
    //   creates a temporary contract to force send the ETH via `SELFDESTRUCT`.
    //   Future compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758.
    // - Reverts if the current contract has insufficient balance.
    //
    // The try variants:
    // - Forwards with a mandatory gas stipend.
    // - Instead of reverting, returns whether the transfer succeeded.

    /// @dev Sends `amount` (in wei) ETH to `to`.
    function safeTransferETH(address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(call(gas(), to, amount, codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Sends all the ETH in the current contract to `to`.
    function safeTransferAllETH(address to) internal {
        /// @solidity memory-safe-assembly
        assembly {
            // Transfer all the ETH and check if it succeeded or not.
            if iszero(call(gas(), to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Force sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
    function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if lt(selfbalance(), amount) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
            if iszero(call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Force sends all the ETH in the current contract to `to`, with a `gasStipend`.
    function forceSafeTransferAllETH(address to, uint256 gasStipend) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Force sends `amount` (in wei) ETH to `to`, with `GAS_STIPEND_NO_GRIEF`.
    function forceSafeTransferETH(address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if lt(selfbalance(), amount) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
            if iszero(call(GAS_STIPEND_NO_GRIEF, to, amount, codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Force sends all the ETH in the current contract to `to`, with `GAS_STIPEND_NO_GRIEF`.
    function forceSafeTransferAllETH(address to) internal {
        /// @solidity memory-safe-assembly
        assembly {
            // forgefmt: disable-next-item
            if iszero(call(GAS_STIPEND_NO_GRIEF, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
    function trySafeTransferETH(address to, uint256 amount, uint256 gasStipend)
        internal
        returns (bool success)
    {
        /// @solidity memory-safe-assembly
        assembly {
            success := call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)
        }
    }

    /// @dev Sends all the ETH in the current contract to `to`, with a `gasStipend`.
    function trySafeTransferAllETH(address to, uint256 gasStipend)
        internal
        returns (bool success)
    {
        /// @solidity memory-safe-assembly
        assembly {
            success := call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      ERC20 OPERATIONS                      */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
    /// Reverts upon failure.
    ///
    /// The `from` account must have at least `amount` approved for
    /// the current contract to manage.
    function safeTransferFrom(address token, address from, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x60, amount) // Store the `amount` argument.
            mstore(0x40, to) // Store the `to` argument.
            mstore(0x2c, shl(96, from)) // Store the `from` argument.
            mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`.
            // Perform the transfer, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Sends all of ERC20 `token` from `from` to `to`.
    /// Reverts upon failure.
    ///
    /// The `from` account must have their entire balance approved for
    /// the current contract to manage.
    function safeTransferAllFrom(address token, address from, address to)
        internal
        returns (uint256 amount)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x40, to) // Store the `to` argument.
            mstore(0x2c, shl(96, from)) // Store the `from` argument.
            mstore(0x0c, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
            // Read the balance, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                    staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20)
                )
            ) {
                mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x00, 0x23b872dd) // `transferFrom(address,address,uint256)`.
            amount := mload(0x60) // The `amount` is already at 0x60. We'll need to return it.
            // Perform the transfer, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Sends `amount` of ERC20 `token` from the current contract to `to`.
    /// Reverts upon failure.
    function safeTransfer(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
            // Perform the transfer, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Sends all of ERC20 `token` from the current contract to `to`.
    /// Reverts upon failure.
    function safeTransferAll(address token, address to) internal returns (uint256 amount) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`.
            mstore(0x20, address()) // Store the address of the current contract.
            // Read the balance, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                    staticcall(gas(), token, 0x1c, 0x24, 0x34, 0x20)
                )
            ) {
                mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x14, to) // Store the `to` argument.
            amount := mload(0x34) // The `amount` is already at 0x34. We'll need to return it.
            mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
            // Perform the transfer, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
    /// Reverts upon failure.
    function safeApprove(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
            // Perform the approval, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
    /// If the initial attempt to approve fails, attempts to reset the approved amount to zero,
    /// then retries the approval again (some tokens, e.g. USDT, requires this).
    /// Reverts upon failure.
    function safeApproveWithRetry(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
            // Perform the approval, retrying upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                mstore(0x34, 0) // Store 0 for the `amount`.
                mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
                pop(call(gas(), token, 0, 0x10, 0x44, codesize(), 0x00)) // Reset the approval.
                mstore(0x34, amount) // Store back the original `amount`.
                // Retry the approval, reverting upon failure.
                if iszero(
                    and(
                        or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                        call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                    )
                ) {
                    mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
                    revert(0x1c, 0x04)
                }
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Returns the amount of ERC20 `token` owned by `account`.
    /// Returns zero if the `token` does not exist.
    function balanceOf(address token, address account) internal view returns (uint256 amount) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, account) // Store the `account` argument.
            mstore(0x00, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
            amount :=
                mul(
                    mload(0x20),
                    and( // The arguments of `and` are evaluated from right to left.
                        gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                        staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20)
                    )
                )
        }
    }
}

File 3 of 3 : MetadataReaderLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Library for reading contract metadata robustly.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/MetadataReaderLib.sol)
library MetadataReaderLib {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         CONSTANTS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Default gas stipend for contract reads. High enough for most practical use cases
    /// (able to SLOAD about 1000 bytes of data), but low enough to prevent griefing.
    uint256 internal constant GAS_STIPEND_NO_GRIEF = 100000;

    /// @dev Default string byte length limit.
    uint256 internal constant STRING_LIMIT_DEFAULT = 1000;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                METADATA READING OPERATIONS                 */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // Best-effort string reading operations.
    // Should NOT revert as long as sufficient gas is provided.
    //
    // Performs the following in order:
    // 1. Returns the empty string for the following cases:
    //     - Reverts.
    //     - No returndata (e.g. function returns nothing, EOA).
    //     - Returns empty string.
    // 2. Attempts to `abi.decode` the returndata into a string.
    // 3. With any remaining gas, scans the returndata from start to end for the
    //    null byte '\0', to interpret the returndata as a null-terminated string.

    /// @dev Equivalent to `readString(abi.encodeWithSignature("name()"))`.
    function readName(address target) internal view returns (string memory) {
        return _string(target, _ptr(0x06fdde03), STRING_LIMIT_DEFAULT, GAS_STIPEND_NO_GRIEF);
    }

    /// @dev Equivalent to `readString(abi.encodeWithSignature("name()"), limit)`.
    function readName(address target, uint256 limit) internal view returns (string memory) {
        return _string(target, _ptr(0x06fdde03), limit, GAS_STIPEND_NO_GRIEF);
    }

    /// @dev Equivalent to `readString(abi.encodeWithSignature("name()"), limit, gasStipend)`.
    function readName(address target, uint256 limit, uint256 gasStipend)
        internal
        view
        returns (string memory)
    {
        return _string(target, _ptr(0x06fdde03), limit, gasStipend);
    }

    /// @dev Equivalent to `readString(abi.encodeWithSignature("symbol()"))`.
    function readSymbol(address target) internal view returns (string memory) {
        return _string(target, _ptr(0x95d89b41), STRING_LIMIT_DEFAULT, GAS_STIPEND_NO_GRIEF);
    }

    /// @dev Equivalent to `readString(abi.encodeWithSignature("symbol()"), limit)`.
    function readSymbol(address target, uint256 limit) internal view returns (string memory) {
        return _string(target, _ptr(0x95d89b41), limit, GAS_STIPEND_NO_GRIEF);
    }

    /// @dev Equivalent to `readString(abi.encodeWithSignature("symbol()"), limit, gasStipend)`.
    function readSymbol(address target, uint256 limit, uint256 gasStipend)
        internal
        view
        returns (string memory)
    {
        return _string(target, _ptr(0x95d89b41), limit, gasStipend);
    }

    /// @dev Performs a best-effort string query on `target` with `data` as the calldata.
    /// The string will be truncated to `STRING_LIMIT_DEFAULT` (1000) bytes.
    function readString(address target, bytes memory data) internal view returns (string memory) {
        return _string(target, _ptr(data), STRING_LIMIT_DEFAULT, GAS_STIPEND_NO_GRIEF);
    }

    /// @dev Performs a best-effort string query on `target` with `data` as the calldata.
    /// The string will be truncated to `limit` bytes.
    function readString(address target, bytes memory data, uint256 limit)
        internal
        view
        returns (string memory)
    {
        return _string(target, _ptr(data), limit, GAS_STIPEND_NO_GRIEF);
    }

    /// @dev Performs a best-effort string query on `target` with `data` as the calldata.
    /// The string will be truncated to `limit` bytes.
    function readString(address target, bytes memory data, uint256 limit, uint256 gasStipend)
        internal
        view
        returns (string memory)
    {
        return _string(target, _ptr(data), limit, gasStipend);
    }

    // Best-effort unsigned integer reading operations.
    // Should NOT revert as long as sufficient gas is provided.
    //
    // Performs the following in order:
    // 1. Attempts to `abi.decode` the result into a uint256
    //    (equivalent across all Solidity uint types, downcast as needed).
    // 2. Returns zero for the following cases:
    //     - Reverts.
    //     - No returndata (e.g. function returns nothing, EOA).
    //     - Returns zero.
    //     - `abi.decode` failure.

    /// @dev Equivalent to `uint8(readUint(abi.encodeWithSignature("decimal()")))`.
    function readDecimals(address target) internal view returns (uint8) {
        return uint8(_uint(target, _ptr(0x313ce567), GAS_STIPEND_NO_GRIEF));
    }

    /// @dev Equivalent to `uint8(readUint(abi.encodeWithSignature("decimal()"), gasStipend))`.
    function readDecimals(address target, uint256 gasStipend) internal view returns (uint8) {
        return uint8(_uint(target, _ptr(0x313ce567), gasStipend));
    }

    /// @dev Performs a best-effort uint query on `target` with `data` as the calldata.
    function readUint(address target, bytes memory data) internal view returns (uint256) {
        return _uint(target, _ptr(data), GAS_STIPEND_NO_GRIEF);
    }

    /// @dev Performs a best-effort uint query on `target` with `data` as the calldata.
    function readUint(address target, bytes memory data, uint256 gasStipend)
        internal
        view
        returns (uint256)
    {
        return _uint(target, _ptr(data), gasStipend);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      PRIVATE HELPERS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Attempts to read and return a string at `target`.
    function _string(address target, bytes32 ptr, uint256 limit, uint256 gasStipend)
        private
        view
        returns (string memory result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            function min(x_, y_) -> _z {
                _z := xor(x_, mul(xor(x_, y_), lt(y_, x_)))
            }
            for {} staticcall(gasStipend, target, add(ptr, 0x20), mload(ptr), 0x00, 0x20) {} {
                let m := mload(0x40) // Grab the free memory pointer.
                let s := add(0x20, m) // Start of the string's bytes in memory.
                // Attempt to `abi.decode` if the returndatasize is greater or equal to 64.
                if iszero(lt(returndatasize(), 0x40)) {
                    let o := mload(0x00) // Load the string's offset in the returndata.
                    // If the string's offset is within bounds.
                    if iszero(gt(o, sub(returndatasize(), 0x20))) {
                        returndatacopy(m, o, 0x20) // Copy the string's length.
                        // If the full string's end is within bounds.
                        // Note: If the full string doesn't fit, the `abi.decode` must be aborted
                        // for compliance purposes, regardless if the truncated string can fit.
                        if iszero(gt(mload(m), sub(returndatasize(), add(o, 0x20)))) {
                            let n := min(mload(m), limit) // Truncate if needed.
                            mstore(m, n) // Overwrite the length.
                            returndatacopy(s, add(o, 0x20), n) // Copy the string's bytes.
                            mstore(add(s, n), 0) // Zeroize the slot after the string.
                            mstore(0x40, add(0x20, add(s, n))) // Allocate memory for the string.
                            result := m
                            break
                        }
                    }
                }
                // Try interpreting as a null-terminated string.
                let n := min(returndatasize(), limit) // Truncate if needed.
                returndatacopy(s, 0, n) // Copy the string's bytes.
                mstore8(add(s, n), 0) // Place a '\0' at the end.
                let i := s // Pointer to the next byte to scan.
                for {} byte(0, mload(i)) { i := add(i, 1) } {} // Scan for '\0'.
                mstore(m, sub(i, s)) // Store the string's length.
                mstore(i, 0) // Zeroize the slot after the string.
                mstore(0x40, add(0x20, i)) // Allocate memory for the string.
                result := m
                break
            }
        }
    }

    /// @dev Attempts to read and return a uint at `target`.
    function _uint(address target, bytes32 ptr, uint256 gasStipend)
        private
        view
        returns (uint256 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            result :=
                mul(
                    mload(0x20),
                    and( // The arguments of `and` are evaluated from right to left.
                        gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                        staticcall(gasStipend, target, add(ptr, 0x20), mload(ptr), 0x20, 0x20)
                    )
                )
        }
    }

    /// @dev Casts the function selector `s` into a pointer.
    function _ptr(uint256 s) private pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            // Layout the calldata in the scratch space for temporary usage.
            mstore(0x04, s) // Store the function selector.
            mstore(result, 4) // Store the length.
        }
    }

    /// @dev Casts the `data` into a pointer.
    function _ptr(bytes memory data) private pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := data
        }
    }
}

Settings
{
  "remappings": [
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/",
    "solady/=lib/solady/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 9999999
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "shanghai",
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"payable","type":"constructor"},{"inputs":[],"name":"InvalidCharacter","type":"error"},{"inputs":[],"name":"InvalidSwap","type":"error"},{"inputs":[],"name":"InvalidSyntax","type":"error"},{"inputs":[],"name":"Overflow","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"string","name":"name","type":"string"}],"name":"NameSet","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[{"internalType":"string","name":"intent","type":"string"},{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"initCode","type":"bytes"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bytes32","name":"accountGasLimits","type":"bytes32"},{"internalType":"uint256","name":"preVerificationGas","type":"uint256"},{"internalType":"bytes32","name":"gasFees","type":"bytes32"},{"internalType":"bytes","name":"paymasterAndData","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct IE.PackedUserOperation","name":"userOp","type":"tuple"}],"name":"checkPackedUserOp","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"intent","type":"string"},{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"initCode","type":"bytes"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"uint256","name":"callGasLimit","type":"uint256"},{"internalType":"uint256","name":"verificationGasLimit","type":"uint256"},{"internalType":"uint256","name":"preVerificationGas","type":"uint256"},{"internalType":"uint256","name":"maxFeePerGas","type":"uint256"},{"internalType":"uint256","name":"maxPriorityFeePerGas","type":"uint256"},{"internalType":"bytes","name":"paymasterAndData","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct IE.UserOperation","name":"userOp","type":"tuple"}],"name":"checkUserOp","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"intent","type":"string"}],"name":"command","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"string","name":"intent","type":"string"}],"name":"previewCommand","outputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"token","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bytes","name":"executeCallData","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"to","type":"string"},{"internalType":"string","name":"amount","type":"string"},{"internalType":"string","name":"token","type":"string"}],"name":"previewSend","outputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bytes","name":"executeCallData","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"amountIn","type":"string"},{"internalType":"string","name":"tokenIn","type":"string"},{"internalType":"string","name":"tokenOut","type":"string"}],"name":"previewSwap","outputs":[{"internalType":"uint256","name":"_amountIn","type":"uint256"},{"internalType":"address","name":"_tokenIn","type":"address"},{"internalType":"address","name":"_tokenOut","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"to","type":"string"},{"internalType":"string","name":"amount","type":"string"},{"internalType":"string","name":"token","type":"string"}],"name":"send","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"string","name":"name","type":"string"}],"name":"setName","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"setNameAndTicker","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"string","name":"amountIn","type":"string"},{"internalType":"string","name":"tokenIn","type":"string"},{"internalType":"string","name":"tokenOut","type":"string"}],"name":"swap","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"}],"name":"tokens","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"}],"name":"whatIsTheAddressOf","outputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"bytes32","name":"node","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"token","type":"string"}],"name":"whatIsTheBalanceOf","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"balanceAdjusted","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"token","type":"string"}],"name":"whatIsTheTotalSupplyOf","outputs":[{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"uint256","name":"supplyAdjusted","type":"uint256"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

60806040525f5b6040518060800160405280604481526020016200309d604491395181146200012b575f6040518060800160405280604481526020016200309d6044913982600101815181106200005a576200005a62000132565b01602001517fff000000000000000000000000000000000000000000000000000000000000001690505f5b6040518060800160405280604481526020016200309d604491398381518110620000b357620000b362000132565b60209101015160f81c60ff82161462000120576001805480820182555f829052602081047fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf601805460f886901c601f9093166101000a92830260ff90930219169190911790550162000085565b505060020162000006565b5062000146565b634e487b7160e01b5f52603260045260245ffd5b612f4980620001545f395ff3fe6080604052600436106100e0575f3560e01c80635fcc45001161007e578063b695b01611610058578063b695b01614610460578063bf0213cd14610473578063bfe686761461048d578063c47d04e2146104ac57610134565b80635fcc4500146103cd5780638b9c93d4146103e0578063aa3aa1421461040f57610134565b80632d8f63db116100ba5780632d8f63db146103585780633121db1c146103775780633e7043851461038a5780635615264d146103ba57610134565b806304c2320b1461029b578063109fe41f14610311578063258cbaf11461034557610134565b36610134573373c02aaa39b223fe8d0a0e5c4f27ead9083c756cc214610132576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b005b6004356024356084355f90811a90608535811a90608635606090811c91609a35821c9160ae35901c90871380159061016c57505f8613155b156101a3576040517f1115766700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f806101af84846104fe565b90925090503373ffffffffffffffffffffffffffffffffffffffff831614610203576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b86156102225761021d8161021757886105dd565b896105dd565b610253565b610253853383610232578a610234565b8b5b73ffffffffffffffffffffffffffffffffffffffff881692919061063b565b8515610132575f816102655789610267565b885b61027090612698565b905061027b81610693565b61013273ffffffffffffffffffffffffffffffffffffffff8716826106c0565b3480156102a6575f80fd5b506102e76102b53660046127a2565b80516020818301810180515f8252928201919093012091525473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561031c575f80fd5b5061033061032b366004612812565b6106dd565b60408051928352602083019190915201610308565b610132610353366004612875565b610814565b348015610363575f80fd5b50610330610372366004612890565b610996565b6101326103853660046128f7565b610b42565b348015610395575f80fd5b506103a96103a4366004612948565b610c6d565b604051610308959493929190612a35565b6101326103c8366004612948565b610e9e565b6101326103db366004612812565b610fc9565b3480156103eb575f80fd5b506103ff6103fa366004612a91565b611134565b6040519015158152602001610308565b34801561041a575f80fd5b5061042e610429366004612948565b61119f565b6040805193845273ffffffffffffffffffffffffffffffffffffffff9283166020850152911690820152606001610308565b61013261046e366004612948565b6112c3565b34801561047e575f80fd5b506103ff6103fa366004612afc565b348015610498575f80fd5b506103a96104a7366004612812565b6115b7565b3480156104b7575f80fd5b506104cb6104c63660046127a2565b611719565b6040805173ffffffffffffffffffffffffffffffffffffffff948516815293909216602084015290820152606001610308565b5f808273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16101561053c57506001610540565b9192915b61054d8484610bb86119a2565b91508173ffffffffffffffffffffffffffffffffffffffff163b5f036105d65761057a84846101f46119a2565b91508173ffffffffffffffffffffffffffffffffffffffff163b5f036105d6576105a6848460646119a2565b91508173ffffffffffffffffffffffffffffffffffffffff163b5f036105d6576105d384846127106119a2565b91505b9250929050565b5f385f388473c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25af15033601452806034526fa9059cbb0000000000000000000000005f525f38604460105f73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25af1505f60345250565b60405181606052826040528360601b602c526f23b872dd000000000000000000000000600c5260205f6064601c5f895af13d1560015f5114171661068657637939f4245f526004601cfd5b5f60605260405250505050565b632e1a7d4d5f52806020525f386024601c5f73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25af15050565b5f385f3884865af16106d95763b12d13eb5f526004601cfd5b5050565b5f80806106f26106ed8587612b5c565b611a4f565b905073ffffffffffffffffffffffffffffffffffffffff8116610749575f8585604051610720929190612b98565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff1690505b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8216016107b8576040517f1e3382cb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6318160ddd5f526020806004601c845afa6107d1575f38fd5b60205192506107f58173ffffffffffffffffffffffffffffffffffffffff16611c9d565b61080090600a612cc5565b61080a9084612cd3565b9150509250929050565b5f61083c6108378373ffffffffffffffffffffffffffffffffffffffff16611cbf565b611ce5565b90505f6108616108378473ffffffffffffffffffffffffffffffffffffffff16611d6c565b9050825f836040516108739190612d0b565b908152604051908190036020018120805473ffffffffffffffffffffffffffffffffffffffff939093167fffffffffffffffffffffffff0000000000000000000000000000000000000000909316831790557fa4cea56cd77acc2291276688ddfb9e3144c5dc056ada99eed3cd0460fbeda175906108f2908590612d26565b60405180910390a2825f8260405161090a9190612d0b565b908152604051908190036020018120805473ffffffffffffffffffffffffffffffffffffffff939093167fffffffffffffffffffffffff0000000000000000000000000000000000000000909316831790557fa4cea56cd77acc2291276688ddfb9e3144c5dc056ada99eed3cd0460fbeda17590610989908490612d26565b60405180910390a2505050565b5f805f6109d787878080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061171992505050565b509150505f610a1a86868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611ce592505050565b90505f610a296106ed83612d38565b905073ffffffffffffffffffffffffffffffffffffffff8116610a80575f8787604051610a57929190612b98565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff1690505b73ffffffffffffffffffffffffffffffffffffffff811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1480610ad757610ad273ffffffffffffffffffffffffffffffffffffffff831685611d86565b610af0565b8373ffffffffffffffffffffffffffffffffffffffff16315b955080610b1b57610b168273ffffffffffffffffffffffffffffffffffffffff16611c9d565b610b1e565b60125b610b2990600a612cc5565b610b339087612cd3565b94505050505094509492505050565b3373da000000000000d2885f108500803dfbaab2f2aa14610b8f576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f610bce83838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611ce592505050565b9050835f82604051610be09190612d0b565b908152604051908190036020018120805473ffffffffffffffffffffffffffffffffffffffff939093167fffffffffffffffffffffffff0000000000000000000000000000000000000000909316831790557fa4cea56cd77acc2291276688ddfb9e3144c5dc056ada99eed3cd0460fbeda17590610c5f908490612d26565b60405180910390a250505050565b5f8080606080610c7f6106ed87612d38565b925073ffffffffffffffffffffffffffffffffffffffff8316610cd4575f86604051610cab9190612d0b565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff1692505b73ffffffffffffffffffffffffffffffffffffffff831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14610d0a89611719565b509650610d4390508882610d3c57610d378673ffffffffffffffffffffffffffffffffffffffff16611c9d565b611db9565b6012611db9565b945080610dec5760405173ffffffffffffffffffffffffffffffffffffffff8716602482015260448101869052606401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905292505b80610df75783610df9565b855b81610e04575f610e06565b855b84604051602401610e1993929190612d7a565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fb61d27f60000000000000000000000000000000000000000000000000000000017905295999498509296509094505050565b5f610eab6106ed83612d38565b905073ffffffffffffffffffffffffffffffffffffffff8116610f00575f82604051610ed79190612d0b565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff1690505b5f610f0a85611719565b509150507fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff831601610f7b57610f76610f59856012611db9565b73ffffffffffffffffffffffffffffffffffffffff8316906106c0565b610fc2565b610fc23382610fa387610d378773ffffffffffffffffffffffffffffffffffffffff16611c9d565b73ffffffffffffffffffffffffffffffffffffffff861692919061063b565b5050505050565b5f61100883838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611ce592505050565b90505f61101482611fa6565b9050807f73656e640000000000000000000000000000000000000000000000000000000014806110635750807f7472616e73666572000000000000000000000000000000000000000000000000145b1561108d575f805f61107485611fe6565b925092509250611085838383610e9e565b50505061112e565b807f737761700000000000000000000000000000000000000000000000000000000014806110da5750807f65786368616e6765000000000000000000000000000000000000000000000000145b156110fc575f805f6110eb856120d7565b9250925092506110858383836112c3565b6040517f1e3382cb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b5f8061114085856115b7565b9450505050508280606001906111569190612db7565b9050815114611168575f915050611198565b6111756060840184612db7565b604051611183929190612b98565b60405180910390208180519060200120149150505b9392505050565b5f80806111ae6106ed86612d38565b915073ffffffffffffffffffffffffffffffffffffffff8216611203575f856040516111da9190612d0b565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff1691505b61120f6106ed85612d38565b905073ffffffffffffffffffffffffffffffffffffffff8116611264575f8460405161123b9190612d0b565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff1690505b6112b88673ffffffffffffffffffffffffffffffffffffffff841673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14610d3c57610d378473ffffffffffffffffffffffffffffffffffffffff16611c9d565b925093509350939050565b5f6112d06106ed84612d38565b905073ffffffffffffffffffffffffffffffffffffffff8116611325575f836040516112fc9190612d0b565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff1690505b5f6113326106ed84612d38565b905073ffffffffffffffffffffffffffffffffffffffff8116611387575f8360405161135e9190612d0b565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff1690505b73ffffffffffffffffffffffffffffffffffffffff82811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee9081149183161481156113d95773c02aaa39b223fe8d0a0e5c4f27ead9083c756cc293505b80156113f75773c02aaa39b223fe8d0a0e5c4f27ead9083c756cc292505b5f6114208884610d3c57610d378773ffffffffffffffffffffffffffffffffffffffff16611c9d565b90507f8000000000000000000000000000000000000000000000000000000000000000811061147b576040517f35278d1200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8061148787876104fe565b915091508173ffffffffffffffffffffffffffffffffffffffff1663128acb0885156114b357306114b5565b335b8386856114d65773fffd8963efd1fc6a506488495d951d5263988d256114dd565b6401000276a45b6040518b151560f890811b60208301528b1515901b60218201527fffffffffffffffffffffffffffffffffffffffff00000000000000000000000033606090811b821660228401528f811b821660368401528e901b16604a820152605e016040516020818303038152906040526040518663ffffffff1660e01b815260040161156a959493929190612e18565b60408051808303815f875af1158015611585573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115a99190612e69565b505050505050505050505050565b5f805f6060805f6115fc88888080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611ce592505050565b90505f61160882611fa6565b9050807f73656e640000000000000000000000000000000000000000000000000000000014806116575750807f7472616e73666572000000000000000000000000000000000000000000000000145b1561168e575f805f61166885611fe6565b925092509250611679838383610c6d565b939d50919b5099509750955061170d92505050565b807f737761700000000000000000000000000000000000000000000000000000000014806116db5750807f65786368616e6765000000000000000000000000000000000000000000000000145b156110fc575f805f6116ec856120d7565b9250925092506116fd83838361119f565b9b50909950975061170d92505050565b50509295509295909350565b5f805f611744846040516020016117309190612e8b565b60405160208183030381529060405261215b565b6040517f02571be3000000000000000000000000000000000000000000000000000000008152600481018290529091506e0c2e074ec69a0dfb2997ba6c7d2e1e906302571be390602401602060405180830381865afa1580156117a9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117cd9190612ecb565b92507fffffffffffffffffffffffff2bbe94ec2d4c5654518532a293d44241da979bff73ffffffffffffffffffffffffffffffffffffffff84160161189a576040517f6352211e0000000000000000000000000000000000000000000000000000000081526004810182905273d4416b13d2b3a9abae7acd5d6c2bbdbe2568640190636352211e90602401602060405180830381865afa158015611873573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118979190612ecb565b92505b6040517f0178b8bf000000000000000000000000000000000000000000000000000000008152600481018290526e0c2e074ec69a0dfb2997ba6c7d2e1e90630178b8bf90602401602060405180830381865afa1580156118fc573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119209190612ecb565b73ffffffffffffffffffffffffffffffffffffffff16633b3b57de826040518263ffffffff1660e01b815260040161195a91815260200190565b602060405180830381865afa158015611975573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119999190612ecb565b91509193909250565b6040805173ffffffffffffffffffffffffffffffffffffffff808616602083015284169181019190915262ffffff821660608201525f90819060800160405160208183030381529060405280519060200120905060ff5f537fe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54603552731f98431c8ad98523631ae4a59f267346ea31f98460601b6001528060155260555f2091505f603552509392505050565b5f817f65746800000000000000000000000000000000000000000000000000000000001480611a9d5750817f6574686572000000000000000000000000000000000000000000000000000000145b15611abd575073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee919050565b817f757364630000000000000000000000000000000000000000000000000000000003611aff575073a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48919050565b817f757364740000000000000000000000000000000000000000000000000000000003611b41575073dac17f958d2ee523a2206206994597c13d831ec7919050565b817f646169000000000000000000000000000000000000000000000000000000000003611b835750736b175474e89094c44da98b954eedeac495271d0f919050565b817f6e616e690000000000000000000000000000000000000000000000000000000003611bbf57506d25824328358250920b271f348690919050565b817f776574680000000000000000000000000000000000000000000000000000000003611c01575073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2919050565b817f77627463000000000000000000000000000000000000000000000000000000001480611c4e5750817f6274630000000000000000000000000000000000000000000000000000000000145b80611c785750817f626974636f696e00000000000000000000000000000000000000000000000000145b15611c985750732260fac5e5542a773aa44fbcfedf7c193bc2c599919050565b919050565b63313ce56760049081525f908152611cb98282620186a0612362565b92915050565b6060611cb982611cd96306fdde0360049081525f90815290565b6103e8620186a0612381565b606081518015611d66576040516001939093019260200191506bffffffc000000000000000007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff825b81018581015160ff1683811c6020168118868301535080611d2e5750505060405191508082528060208301015f815260208101604052505b50919050565b6060611cb982611cd96395d89b4160049081525f90815290565b5f816014526f70a082310000000000000000000000005f5260208060246010865afa601f3d111660205102905092915050565b5f808084815b81518114611f83577f3000000000000000000000000000000000000000000000000000000000000000828281518110611dfa57611dfa612ee6565b01602001517fff000000000000000000000000000000000000000000000000000000000000001610801590611e8757507f3900000000000000000000000000000000000000000000000000000000000000828281518110611e5d57611e5d612ee6565b01602001517fff000000000000000000000000000000000000000000000000000000000000001611155b15611ed5576030828281518110611ea057611ea0612ee6565b602001015160f81c60f81b60f81c60ff1686600a02010394508315611ed0578260010192508560ff168311611f83575b611f7b565b818181518110611ee757611ee7612ee6565b6020910101517fff00000000000000000000000000000000000000000000000000000000000000167f2e00000000000000000000000000000000000000000000000000000000000000148015611f3b575083155b15611f495760019350611f7b565b6040517f312a9f5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600101611dbf565b508460ff16821015611f9d57818560ff1603600a0a840293505b50505092915050565b5f602082015f5b6020811015611fdf57808201515f1a60208103611fca5750611fdf565b6008820260f8031b9290921791600101611fad565b5050919050565b60608060605f612016857f200000000000000000000000000000000000000000000000000000000000000061242a565b9050805160040361207e578060018151811061203457612034612ee6565b60200260200101518160028151811061204f5761204f612ee6565b60200260200101518260038151811061206a5761206a612ee6565b6020026020010151935093509350506120d0565b80516005036110fc578060048151811061209a5761209a612ee6565b6020026020010151816001815181106120b5576120b5612ee6565b60200260200101518260028151811061206a5761206a612ee6565b9193909250565b60608060605f612107857f200000000000000000000000000000000000000000000000000000000000000061242a565b905080516005036110fc578060018151811061212557612125612ee6565b60200260200101518160028151811061214057612140612ee6565b60200260200101518260048151811061206a5761206a612ee6565b80515f90805b8115612325575f84600184038151811061217d5761217d612ee6565b01602001517fff000000000000000000000000000000000000000000000000000000000000001690507f2e0000000000000000000000000000000000000000000000000000000000000081900361221057828203602084870101208490604080516020810193909352820152606001604051602081830303815290604052805190602001209350600183039150506122fb565b7f80000000000000000000000000000000000000000000000000000000000000007fff0000000000000000000000000000000000000000000000000000000000000082161061225d575f80fd5b5f60018260f81c60ff168154811061227757612277612ee6565b5f91825260208083209082040154601f9091166101000a900460f81b915060ff1660f882901c036122a6575f80fd5b600160f882901c11156122f857808660018603815181106122c9576122c9612ee6565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505b50505b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90910190612161565b8181036020838601012083906040805160208101939093528201526060016040516020818303038152906040528051906020012092505050919050565b5f6020808451602086018786fa601f3d11166020510290509392505050565b606060205f8551602087018886fa15612422576040518060200160403d106123eb575f5160203d0381116123e957602081843e602081013d038351116123e957825186811181881802188084528060208301843e5f9201918252506020016040529050612422565b505b3d8581118187180218805f833e5f8183015350805b80515f1a1561241157600101612400565b90810382525f815260200160405290505b949350505050565b60608260015f5b825181146124a957847effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191683828151811061246e5761246e612ee6565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016036124a1578160010191505b600101612431565b508067ffffffffffffffff8111156124c3576124c36126ce565b6040519080825280602002602001820160405280156124f657816020015b60608152602001906001900390816124e15790505b5092505f805f5b8451811161266057845181148061256d5750867effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191685828151811061254457612544612ee6565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016145b15612658575f82820367ffffffffffffffff81111561258e5761258e6126ce565b6040519080825280601f01601f1916602001820160405280156125b8576020820181803683370190505b509050825b82811461262b578681815181106125d6576125d6612ee6565b602001015160f81c60f81b82858303815181106125f5576125f5612ee6565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053506001016125bd565b508087858151811061263f5761263f612ee6565b6020026020010181905250836001019350816001019250505b6001016124fd565b505050505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f7f800000000000000000000000000000000000000000000000000000000000000082036126c8576126c861266b565b505f0390565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f82601f83011261270a575f80fd5b813567ffffffffffffffff80821115612725576127256126ce565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190828211818310171561276b5761276b6126ce565b81604052838152866020858801011115612783575f80fd5b836020870160208301375f602085830101528094505050505092915050565b5f602082840312156127b2575f80fd5b813567ffffffffffffffff8111156127c8575f80fd5b612422848285016126fb565b5f8083601f8401126127e4575f80fd5b50813567ffffffffffffffff8111156127fb575f80fd5b6020830191508360208285010111156105d6575f80fd5b5f8060208385031215612823575f80fd5b823567ffffffffffffffff811115612839575f80fd5b612845858286016127d4565b90969095509350505050565b73ffffffffffffffffffffffffffffffffffffffff81168114612872575f80fd5b50565b5f60208284031215612885575f80fd5b813561119881612851565b5f805f80604085870312156128a3575f80fd5b843567ffffffffffffffff808211156128ba575f80fd5b6128c6888389016127d4565b909650945060208701359150808211156128de575f80fd5b506128eb878288016127d4565b95989497509550505050565b5f805f60408486031215612909575f80fd5b833561291481612851565b9250602084013567ffffffffffffffff81111561292f575f80fd5b61293b868287016127d4565b9497909650939450505050565b5f805f6060848603121561295a575f80fd5b833567ffffffffffffffff80821115612971575f80fd5b61297d878388016126fb565b94506020860135915080821115612992575f80fd5b61299e878388016126fb565b935060408601359150808211156129b3575f80fd5b506129c0868287016126fb565b9150509250925092565b5f5b838110156129e45781810151838201526020016129cc565b50505f910152565b5f8151808452612a038160208601602086016129ca565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b5f73ffffffffffffffffffffffffffffffffffffffff808816835286602084015280861660408401525060a06060830152612a7360a08301856129ec565b8281036080840152612a8581856129ec565b98975050505050505050565b5f805f60408486031215612aa3575f80fd5b833567ffffffffffffffff80821115612aba575f80fd5b612ac6878388016127d4565b90955093506020860135915080821115612ade575f80fd5b5084016101208187031215612af1575f80fd5b809150509250925092565b5f805f60408486031215612b0e575f80fd5b833567ffffffffffffffff80821115612b25575f80fd5b612b31878388016127d4565b90955093506020860135915080821115612b49575f80fd5b5084016101608187031215612af1575f80fd5b80356020831015611cb9577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602084900360031b1b1692915050565b818382375f9101908152919050565b600181815b80851115612c0057817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115612be657612be661266b565b80851615612bf357918102915b93841c9390800290612bac565b509250929050565b5f82612c1657506001611cb9565b81612c2257505f611cb9565b8160018114612c385760028114612c4257612c5e565b6001915050611cb9565b60ff841115612c5357612c5361266b565b50506001821b611cb9565b5060208310610133831016604e8410600b8410161715612c81575081810a611cb9565b612c8b8383612ba7565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115612cbd57612cbd61266b565b029392505050565b5f61119860ff841683612c08565b5f82612d06577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b5f8251612d1c8184602087016129ca565b9190910192915050565b602081525f61119860208301846129ec565b80516020808301519190811015611d66577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60209190910360031b1b16919050565b73ffffffffffffffffffffffffffffffffffffffff84168152826020820152606060408201525f612dae60608301846129ec565b95945050505050565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612dea575f80fd5b83018035915067ffffffffffffffff821115612e04575f80fd5b6020019150368190038213156105d6575f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff8088168352861515602084015285604084015280851660608401525060a06080830152612e5e60a08301846129ec565b979650505050505050565b5f8060408385031215612e7a575f80fd5b505080516020909101519092909150565b5f8251612e9c8184602087016129ca565b7f2e65746800000000000000000000000000000000000000000000000000000000920191825250600401919050565b5f60208284031215612edb575f80fd5b815161119881612851565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffdfea264697066735822122038af376b35a6d498afa7275e4ae0cf9671901c58b82f681a2aa5029bb12be19b64736f6c634300081800332d00020101000a010700016101620163016401650166016701680169016a016b016c016d016e016f0170017101720173017401750176017701780179017a06001a010500

Deployed Bytecode

0x6080604052600436106100e0575f3560e01c80635fcc45001161007e578063b695b01611610058578063b695b01614610460578063bf0213cd14610473578063bfe686761461048d578063c47d04e2146104ac57610134565b80635fcc4500146103cd5780638b9c93d4146103e0578063aa3aa1421461040f57610134565b80632d8f63db116100ba5780632d8f63db146103585780633121db1c146103775780633e7043851461038a5780635615264d146103ba57610134565b806304c2320b1461029b578063109fe41f14610311578063258cbaf11461034557610134565b36610134573373c02aaa39b223fe8d0a0e5c4f27ead9083c756cc214610132576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b005b6004356024356084355f90811a90608535811a90608635606090811c91609a35821c9160ae35901c90871380159061016c57505f8613155b156101a3576040517f1115766700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f806101af84846104fe565b90925090503373ffffffffffffffffffffffffffffffffffffffff831614610203576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b86156102225761021d8161021757886105dd565b896105dd565b610253565b610253853383610232578a610234565b8b5b73ffffffffffffffffffffffffffffffffffffffff881692919061063b565b8515610132575f816102655789610267565b885b61027090612698565b905061027b81610693565b61013273ffffffffffffffffffffffffffffffffffffffff8716826106c0565b3480156102a6575f80fd5b506102e76102b53660046127a2565b80516020818301810180515f8252928201919093012091525473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561031c575f80fd5b5061033061032b366004612812565b6106dd565b60408051928352602083019190915201610308565b610132610353366004612875565b610814565b348015610363575f80fd5b50610330610372366004612890565b610996565b6101326103853660046128f7565b610b42565b348015610395575f80fd5b506103a96103a4366004612948565b610c6d565b604051610308959493929190612a35565b6101326103c8366004612948565b610e9e565b6101326103db366004612812565b610fc9565b3480156103eb575f80fd5b506103ff6103fa366004612a91565b611134565b6040519015158152602001610308565b34801561041a575f80fd5b5061042e610429366004612948565b61119f565b6040805193845273ffffffffffffffffffffffffffffffffffffffff9283166020850152911690820152606001610308565b61013261046e366004612948565b6112c3565b34801561047e575f80fd5b506103ff6103fa366004612afc565b348015610498575f80fd5b506103a96104a7366004612812565b6115b7565b3480156104b7575f80fd5b506104cb6104c63660046127a2565b611719565b6040805173ffffffffffffffffffffffffffffffffffffffff948516815293909216602084015290820152606001610308565b5f808273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16101561053c57506001610540565b9192915b61054d8484610bb86119a2565b91508173ffffffffffffffffffffffffffffffffffffffff163b5f036105d65761057a84846101f46119a2565b91508173ffffffffffffffffffffffffffffffffffffffff163b5f036105d6576105a6848460646119a2565b91508173ffffffffffffffffffffffffffffffffffffffff163b5f036105d6576105d384846127106119a2565b91505b9250929050565b5f385f388473c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25af15033601452806034526fa9059cbb0000000000000000000000005f525f38604460105f73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25af1505f60345250565b60405181606052826040528360601b602c526f23b872dd000000000000000000000000600c5260205f6064601c5f895af13d1560015f5114171661068657637939f4245f526004601cfd5b5f60605260405250505050565b632e1a7d4d5f52806020525f386024601c5f73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25af15050565b5f385f3884865af16106d95763b12d13eb5f526004601cfd5b5050565b5f80806106f26106ed8587612b5c565b611a4f565b905073ffffffffffffffffffffffffffffffffffffffff8116610749575f8585604051610720929190612b98565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff1690505b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8216016107b8576040517f1e3382cb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6318160ddd5f526020806004601c845afa6107d1575f38fd5b60205192506107f58173ffffffffffffffffffffffffffffffffffffffff16611c9d565b61080090600a612cc5565b61080a9084612cd3565b9150509250929050565b5f61083c6108378373ffffffffffffffffffffffffffffffffffffffff16611cbf565b611ce5565b90505f6108616108378473ffffffffffffffffffffffffffffffffffffffff16611d6c565b9050825f836040516108739190612d0b565b908152604051908190036020018120805473ffffffffffffffffffffffffffffffffffffffff939093167fffffffffffffffffffffffff0000000000000000000000000000000000000000909316831790557fa4cea56cd77acc2291276688ddfb9e3144c5dc056ada99eed3cd0460fbeda175906108f2908590612d26565b60405180910390a2825f8260405161090a9190612d0b565b908152604051908190036020018120805473ffffffffffffffffffffffffffffffffffffffff939093167fffffffffffffffffffffffff0000000000000000000000000000000000000000909316831790557fa4cea56cd77acc2291276688ddfb9e3144c5dc056ada99eed3cd0460fbeda17590610989908490612d26565b60405180910390a2505050565b5f805f6109d787878080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061171992505050565b509150505f610a1a86868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611ce592505050565b90505f610a296106ed83612d38565b905073ffffffffffffffffffffffffffffffffffffffff8116610a80575f8787604051610a57929190612b98565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff1690505b73ffffffffffffffffffffffffffffffffffffffff811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1480610ad757610ad273ffffffffffffffffffffffffffffffffffffffff831685611d86565b610af0565b8373ffffffffffffffffffffffffffffffffffffffff16315b955080610b1b57610b168273ffffffffffffffffffffffffffffffffffffffff16611c9d565b610b1e565b60125b610b2990600a612cc5565b610b339087612cd3565b94505050505094509492505050565b3373da000000000000d2885f108500803dfbaab2f2aa14610b8f576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f610bce83838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611ce592505050565b9050835f82604051610be09190612d0b565b908152604051908190036020018120805473ffffffffffffffffffffffffffffffffffffffff939093167fffffffffffffffffffffffff0000000000000000000000000000000000000000909316831790557fa4cea56cd77acc2291276688ddfb9e3144c5dc056ada99eed3cd0460fbeda17590610c5f908490612d26565b60405180910390a250505050565b5f8080606080610c7f6106ed87612d38565b925073ffffffffffffffffffffffffffffffffffffffff8316610cd4575f86604051610cab9190612d0b565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff1692505b73ffffffffffffffffffffffffffffffffffffffff831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14610d0a89611719565b509650610d4390508882610d3c57610d378673ffffffffffffffffffffffffffffffffffffffff16611c9d565b611db9565b6012611db9565b945080610dec5760405173ffffffffffffffffffffffffffffffffffffffff8716602482015260448101869052606401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905292505b80610df75783610df9565b855b81610e04575f610e06565b855b84604051602401610e1993929190612d7a565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fb61d27f60000000000000000000000000000000000000000000000000000000017905295999498509296509094505050565b5f610eab6106ed83612d38565b905073ffffffffffffffffffffffffffffffffffffffff8116610f00575f82604051610ed79190612d0b565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff1690505b5f610f0a85611719565b509150507fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff831601610f7b57610f76610f59856012611db9565b73ffffffffffffffffffffffffffffffffffffffff8316906106c0565b610fc2565b610fc23382610fa387610d378773ffffffffffffffffffffffffffffffffffffffff16611c9d565b73ffffffffffffffffffffffffffffffffffffffff861692919061063b565b5050505050565b5f61100883838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611ce592505050565b90505f61101482611fa6565b9050807f73656e640000000000000000000000000000000000000000000000000000000014806110635750807f7472616e73666572000000000000000000000000000000000000000000000000145b1561108d575f805f61107485611fe6565b925092509250611085838383610e9e565b50505061112e565b807f737761700000000000000000000000000000000000000000000000000000000014806110da5750807f65786368616e6765000000000000000000000000000000000000000000000000145b156110fc575f805f6110eb856120d7565b9250925092506110858383836112c3565b6040517f1e3382cb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b5f8061114085856115b7565b9450505050508280606001906111569190612db7565b9050815114611168575f915050611198565b6111756060840184612db7565b604051611183929190612b98565b60405180910390208180519060200120149150505b9392505050565b5f80806111ae6106ed86612d38565b915073ffffffffffffffffffffffffffffffffffffffff8216611203575f856040516111da9190612d0b565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff1691505b61120f6106ed85612d38565b905073ffffffffffffffffffffffffffffffffffffffff8116611264575f8460405161123b9190612d0b565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff1690505b6112b88673ffffffffffffffffffffffffffffffffffffffff841673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14610d3c57610d378473ffffffffffffffffffffffffffffffffffffffff16611c9d565b925093509350939050565b5f6112d06106ed84612d38565b905073ffffffffffffffffffffffffffffffffffffffff8116611325575f836040516112fc9190612d0b565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff1690505b5f6113326106ed84612d38565b905073ffffffffffffffffffffffffffffffffffffffff8116611387575f8360405161135e9190612d0b565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff1690505b73ffffffffffffffffffffffffffffffffffffffff82811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee9081149183161481156113d95773c02aaa39b223fe8d0a0e5c4f27ead9083c756cc293505b80156113f75773c02aaa39b223fe8d0a0e5c4f27ead9083c756cc292505b5f6114208884610d3c57610d378773ffffffffffffffffffffffffffffffffffffffff16611c9d565b90507f8000000000000000000000000000000000000000000000000000000000000000811061147b576040517f35278d1200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8061148787876104fe565b915091508173ffffffffffffffffffffffffffffffffffffffff1663128acb0885156114b357306114b5565b335b8386856114d65773fffd8963efd1fc6a506488495d951d5263988d256114dd565b6401000276a45b6040518b151560f890811b60208301528b1515901b60218201527fffffffffffffffffffffffffffffffffffffffff00000000000000000000000033606090811b821660228401528f811b821660368401528e901b16604a820152605e016040516020818303038152906040526040518663ffffffff1660e01b815260040161156a959493929190612e18565b60408051808303815f875af1158015611585573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115a99190612e69565b505050505050505050505050565b5f805f6060805f6115fc88888080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611ce592505050565b90505f61160882611fa6565b9050807f73656e640000000000000000000000000000000000000000000000000000000014806116575750807f7472616e73666572000000000000000000000000000000000000000000000000145b1561168e575f805f61166885611fe6565b925092509250611679838383610c6d565b939d50919b5099509750955061170d92505050565b807f737761700000000000000000000000000000000000000000000000000000000014806116db5750807f65786368616e6765000000000000000000000000000000000000000000000000145b156110fc575f805f6116ec856120d7565b9250925092506116fd83838361119f565b9b50909950975061170d92505050565b50509295509295909350565b5f805f611744846040516020016117309190612e8b565b60405160208183030381529060405261215b565b6040517f02571be3000000000000000000000000000000000000000000000000000000008152600481018290529091506e0c2e074ec69a0dfb2997ba6c7d2e1e906302571be390602401602060405180830381865afa1580156117a9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117cd9190612ecb565b92507fffffffffffffffffffffffff2bbe94ec2d4c5654518532a293d44241da979bff73ffffffffffffffffffffffffffffffffffffffff84160161189a576040517f6352211e0000000000000000000000000000000000000000000000000000000081526004810182905273d4416b13d2b3a9abae7acd5d6c2bbdbe2568640190636352211e90602401602060405180830381865afa158015611873573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118979190612ecb565b92505b6040517f0178b8bf000000000000000000000000000000000000000000000000000000008152600481018290526e0c2e074ec69a0dfb2997ba6c7d2e1e90630178b8bf90602401602060405180830381865afa1580156118fc573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119209190612ecb565b73ffffffffffffffffffffffffffffffffffffffff16633b3b57de826040518263ffffffff1660e01b815260040161195a91815260200190565b602060405180830381865afa158015611975573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119999190612ecb565b91509193909250565b6040805173ffffffffffffffffffffffffffffffffffffffff808616602083015284169181019190915262ffffff821660608201525f90819060800160405160208183030381529060405280519060200120905060ff5f537fe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54603552731f98431c8ad98523631ae4a59f267346ea31f98460601b6001528060155260555f2091505f603552509392505050565b5f817f65746800000000000000000000000000000000000000000000000000000000001480611a9d5750817f6574686572000000000000000000000000000000000000000000000000000000145b15611abd575073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee919050565b817f757364630000000000000000000000000000000000000000000000000000000003611aff575073a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48919050565b817f757364740000000000000000000000000000000000000000000000000000000003611b41575073dac17f958d2ee523a2206206994597c13d831ec7919050565b817f646169000000000000000000000000000000000000000000000000000000000003611b835750736b175474e89094c44da98b954eedeac495271d0f919050565b817f6e616e690000000000000000000000000000000000000000000000000000000003611bbf57506d25824328358250920b271f348690919050565b817f776574680000000000000000000000000000000000000000000000000000000003611c01575073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2919050565b817f77627463000000000000000000000000000000000000000000000000000000001480611c4e5750817f6274630000000000000000000000000000000000000000000000000000000000145b80611c785750817f626974636f696e00000000000000000000000000000000000000000000000000145b15611c985750732260fac5e5542a773aa44fbcfedf7c193bc2c599919050565b919050565b63313ce56760049081525f908152611cb98282620186a0612362565b92915050565b6060611cb982611cd96306fdde0360049081525f90815290565b6103e8620186a0612381565b606081518015611d66576040516001939093019260200191506bffffffc000000000000000007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff825b81018581015160ff1683811c6020168118868301535080611d2e5750505060405191508082528060208301015f815260208101604052505b50919050565b6060611cb982611cd96395d89b4160049081525f90815290565b5f816014526f70a082310000000000000000000000005f5260208060246010865afa601f3d111660205102905092915050565b5f808084815b81518114611f83577f3000000000000000000000000000000000000000000000000000000000000000828281518110611dfa57611dfa612ee6565b01602001517fff000000000000000000000000000000000000000000000000000000000000001610801590611e8757507f3900000000000000000000000000000000000000000000000000000000000000828281518110611e5d57611e5d612ee6565b01602001517fff000000000000000000000000000000000000000000000000000000000000001611155b15611ed5576030828281518110611ea057611ea0612ee6565b602001015160f81c60f81b60f81c60ff1686600a02010394508315611ed0578260010192508560ff168311611f83575b611f7b565b818181518110611ee757611ee7612ee6565b6020910101517fff00000000000000000000000000000000000000000000000000000000000000167f2e00000000000000000000000000000000000000000000000000000000000000148015611f3b575083155b15611f495760019350611f7b565b6040517f312a9f5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600101611dbf565b508460ff16821015611f9d57818560ff1603600a0a840293505b50505092915050565b5f602082015f5b6020811015611fdf57808201515f1a60208103611fca5750611fdf565b6008820260f8031b9290921791600101611fad565b5050919050565b60608060605f612016857f200000000000000000000000000000000000000000000000000000000000000061242a565b9050805160040361207e578060018151811061203457612034612ee6565b60200260200101518160028151811061204f5761204f612ee6565b60200260200101518260038151811061206a5761206a612ee6565b6020026020010151935093509350506120d0565b80516005036110fc578060048151811061209a5761209a612ee6565b6020026020010151816001815181106120b5576120b5612ee6565b60200260200101518260028151811061206a5761206a612ee6565b9193909250565b60608060605f612107857f200000000000000000000000000000000000000000000000000000000000000061242a565b905080516005036110fc578060018151811061212557612125612ee6565b60200260200101518160028151811061214057612140612ee6565b60200260200101518260048151811061206a5761206a612ee6565b80515f90805b8115612325575f84600184038151811061217d5761217d612ee6565b01602001517fff000000000000000000000000000000000000000000000000000000000000001690507f2e0000000000000000000000000000000000000000000000000000000000000081900361221057828203602084870101208490604080516020810193909352820152606001604051602081830303815290604052805190602001209350600183039150506122fb565b7f80000000000000000000000000000000000000000000000000000000000000007fff0000000000000000000000000000000000000000000000000000000000000082161061225d575f80fd5b5f60018260f81c60ff168154811061227757612277612ee6565b5f91825260208083209082040154601f9091166101000a900460f81b915060ff1660f882901c036122a6575f80fd5b600160f882901c11156122f857808660018603815181106122c9576122c9612ee6565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505b50505b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90910190612161565b8181036020838601012083906040805160208101939093528201526060016040516020818303038152906040528051906020012092505050919050565b5f6020808451602086018786fa601f3d11166020510290509392505050565b606060205f8551602087018886fa15612422576040518060200160403d106123eb575f5160203d0381116123e957602081843e602081013d038351116123e957825186811181881802188084528060208301843e5f9201918252506020016040529050612422565b505b3d8581118187180218805f833e5f8183015350805b80515f1a1561241157600101612400565b90810382525f815260200160405290505b949350505050565b60608260015f5b825181146124a957847effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191683828151811061246e5761246e612ee6565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016036124a1578160010191505b600101612431565b508067ffffffffffffffff8111156124c3576124c36126ce565b6040519080825280602002602001820160405280156124f657816020015b60608152602001906001900390816124e15790505b5092505f805f5b8451811161266057845181148061256d5750867effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191685828151811061254457612544612ee6565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016145b15612658575f82820367ffffffffffffffff81111561258e5761258e6126ce565b6040519080825280601f01601f1916602001820160405280156125b8576020820181803683370190505b509050825b82811461262b578681815181106125d6576125d6612ee6565b602001015160f81c60f81b82858303815181106125f5576125f5612ee6565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053506001016125bd565b508087858151811061263f5761263f612ee6565b6020026020010181905250836001019350816001019250505b6001016124fd565b505050505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f7f800000000000000000000000000000000000000000000000000000000000000082036126c8576126c861266b565b505f0390565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f82601f83011261270a575f80fd5b813567ffffffffffffffff80821115612725576127256126ce565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190828211818310171561276b5761276b6126ce565b81604052838152866020858801011115612783575f80fd5b836020870160208301375f602085830101528094505050505092915050565b5f602082840312156127b2575f80fd5b813567ffffffffffffffff8111156127c8575f80fd5b612422848285016126fb565b5f8083601f8401126127e4575f80fd5b50813567ffffffffffffffff8111156127fb575f80fd5b6020830191508360208285010111156105d6575f80fd5b5f8060208385031215612823575f80fd5b823567ffffffffffffffff811115612839575f80fd5b612845858286016127d4565b90969095509350505050565b73ffffffffffffffffffffffffffffffffffffffff81168114612872575f80fd5b50565b5f60208284031215612885575f80fd5b813561119881612851565b5f805f80604085870312156128a3575f80fd5b843567ffffffffffffffff808211156128ba575f80fd5b6128c6888389016127d4565b909650945060208701359150808211156128de575f80fd5b506128eb878288016127d4565b95989497509550505050565b5f805f60408486031215612909575f80fd5b833561291481612851565b9250602084013567ffffffffffffffff81111561292f575f80fd5b61293b868287016127d4565b9497909650939450505050565b5f805f6060848603121561295a575f80fd5b833567ffffffffffffffff80821115612971575f80fd5b61297d878388016126fb565b94506020860135915080821115612992575f80fd5b61299e878388016126fb565b935060408601359150808211156129b3575f80fd5b506129c0868287016126fb565b9150509250925092565b5f5b838110156129e45781810151838201526020016129cc565b50505f910152565b5f8151808452612a038160208601602086016129ca565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b5f73ffffffffffffffffffffffffffffffffffffffff808816835286602084015280861660408401525060a06060830152612a7360a08301856129ec565b8281036080840152612a8581856129ec565b98975050505050505050565b5f805f60408486031215612aa3575f80fd5b833567ffffffffffffffff80821115612aba575f80fd5b612ac6878388016127d4565b90955093506020860135915080821115612ade575f80fd5b5084016101208187031215612af1575f80fd5b809150509250925092565b5f805f60408486031215612b0e575f80fd5b833567ffffffffffffffff80821115612b25575f80fd5b612b31878388016127d4565b90955093506020860135915080821115612b49575f80fd5b5084016101608187031215612af1575f80fd5b80356020831015611cb9577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602084900360031b1b1692915050565b818382375f9101908152919050565b600181815b80851115612c0057817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115612be657612be661266b565b80851615612bf357918102915b93841c9390800290612bac565b509250929050565b5f82612c1657506001611cb9565b81612c2257505f611cb9565b8160018114612c385760028114612c4257612c5e565b6001915050611cb9565b60ff841115612c5357612c5361266b565b50506001821b611cb9565b5060208310610133831016604e8410600b8410161715612c81575081810a611cb9565b612c8b8383612ba7565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115612cbd57612cbd61266b565b029392505050565b5f61119860ff841683612c08565b5f82612d06577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b5f8251612d1c8184602087016129ca565b9190910192915050565b602081525f61119860208301846129ec565b80516020808301519190811015611d66577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60209190910360031b1b16919050565b73ffffffffffffffffffffffffffffffffffffffff84168152826020820152606060408201525f612dae60608301846129ec565b95945050505050565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612dea575f80fd5b83018035915067ffffffffffffffff821115612e04575f80fd5b6020019150368190038213156105d6575f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff8088168352861515602084015285604084015280851660608401525060a06080830152612e5e60a08301846129ec565b979650505050505050565b5f8060408385031215612e7a575f80fd5b505080516020909101519092909150565b5f8251612e9c8184602087016129ca565b7f2e65746800000000000000000000000000000000000000000000000000000000920191825250600401919050565b5f60208284031215612edb575f80fd5b815161119881612851565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffdfea264697066735822122038af376b35a6d498afa7275e4ae0cf9671901c58b82f681a2aa5029bb12be19b64736f6c63430008180033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
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.