Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 18 from a total of 18 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Command | 20390029 | 99 days ago | IN | 0 ETH | 0.00044086 | ||||
Command | 20288902 | 113 days ago | IN | 0 ETH | 0.00134962 | ||||
Command | 20270487 | 115 days ago | IN | 0 ETH | 0.00053293 | ||||
Command | 20204023 | 125 days ago | IN | 0.001 ETH | 0.00032328 | ||||
Command | 20183088 | 128 days ago | IN | 0 ETH | 0.00091903 | ||||
Command | 20183083 | 128 days ago | IN | 0 ETH | 0.00080403 | ||||
Command | 20178218 | 128 days ago | IN | 0.00333 ETH | 0.00125631 | ||||
Command | 20178199 | 128 days ago | IN | 0.00333 ETH | 0.0014185 | ||||
Command | 20119801 | 136 days ago | IN | 0.00777 ETH | 0.00127618 | ||||
Command | 20024292 | 150 days ago | IN | 0.001 ETH | 0.00081425 | ||||
Command | 19271385 | 255 days ago | IN | 0 ETH | 0.00599928 | ||||
Command | 19268753 | 256 days ago | IN | 0 ETH | 0.00445912 | ||||
Command | 19268364 | 256 days ago | IN | 0 ETH | 0.00444699 | ||||
Send | 19252805 | 258 days ago | IN | 0.001002 ETH | 0.00121941 | ||||
Command | 19242232 | 259 days ago | IN | 0.001 ETH | 0.00282405 | ||||
Command | 19242122 | 259 days ago | IN | 0.001 ETH | 0.00403443 | ||||
Command | 19241045 | 259 days ago | IN | 0 ETH | 0.005301 | ||||
Command | 19238921 | 260 days ago | IN | 0.01 ETH | 0.00286821 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
20390029 | 99 days ago | 0.01282379 ETH | ||||
20390029 | 99 days ago | 0.01282379 ETH | ||||
20288902 | 113 days ago | 0.00645518 ETH | ||||
20288902 | 113 days ago | 0.00645518 ETH | ||||
20204023 | 125 days ago | 0.001 ETH | ||||
20183088 | 128 days ago | 0.03189631 ETH | ||||
20183088 | 128 days ago | 0.03189631 ETH | ||||
20183083 | 128 days ago | 0.00732854 ETH | ||||
20183083 | 128 days ago | 0.00732854 ETH | ||||
20178218 | 128 days ago | 0.00333 ETH | ||||
20178199 | 128 days ago | 0.00333 ETH | ||||
20119801 | 136 days ago | 0.00777 ETH | ||||
20024292 | 150 days ago | 0.001 ETH | ||||
19268753 | 256 days ago | 0.00340178 ETH | ||||
19268753 | 256 days ago | 0.00340178 ETH | ||||
19268364 | 256 days ago | 0.03695706 ETH | ||||
19268364 | 256 days ago | 0.03695706 ETH | ||||
19252805 | 258 days ago | 0.001002 ETH | ||||
19242232 | 259 days ago | 0.001 ETH | ||||
19242122 | 259 days ago | 0.001 ETH | ||||
19241045 | 259 days ago | 0.00708286 ETH | ||||
19241045 | 259 days ago | 0.00708286 ETH | ||||
19240026 | 260 days ago | 0.001 ETH | ||||
19240026 | 260 days ago | 0.001 ETH | ||||
19238921 | 260 days ago | 0.01 ETH |
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
Contract Source Code (Solidity Standard Json-Input format)
// ⌘ ⌘ ⌘ ⌘ ⌘ ⌘ ⌘ ⌘ ⌘ ⌘ ⌘ ⌘ ⌘ ⌘ ⌘ ⌘ ⌘ ⌘ ⌘ // 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); }
// 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) ) ) } } }
// 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 } } }
{ "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
- No Contract Security Audit Submitted- Submit Audit Here
[{"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"}]
Contract Creation Code
60806040525f5b6040518060800160405280604481526020016200309d604491395181146200012b575f6040518060800160405280604481526020016200309d6044913982600101815181106200005a576200005a62000132565b01602001517fff000000000000000000000000000000000000000000000000000000000000001690505f5b6040518060800160405280604481526020016200309d604491398381518110620000b357620000b362000132565b60209101015160f81c60ff82161462000120576001805480820182555f829052602081047fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf601805460f886901c601f9093166101000a92830260ff90930219169190911790550162000085565b505060020162000006565b5062000146565b634e487b7160e01b5f52603260045260245ffd5b612f4980620001545f395ff3fe6080604052600436106100e0575f3560e01c80635fcc45001161007e578063b695b01611610058578063b695b01614610460578063bf0213cd14610473578063bfe686761461048d578063c47d04e2146104ac57610134565b80635fcc4500146103cd5780638b9c93d4146103e0578063aa3aa1421461040f57610134565b80632d8f63db116100ba5780632d8f63db146103585780633121db1c146103775780633e7043851461038a5780635615264d146103ba57610134565b806304c2320b1461029b578063109fe41f14610311578063258cbaf11461034557610134565b36610134573373c02aaa39b223fe8d0a0e5c4f27ead9083c756cc214610132576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b005b6004356024356084355f90811a90608535811a90608635606090811c91609a35821c9160ae35901c90871380159061016c57505f8613155b156101a3576040517f1115766700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f806101af84846104fe565b90925090503373ffffffffffffffffffffffffffffffffffffffff831614610203576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b86156102225761021d8161021757886105dd565b896105dd565b610253565b610253853383610232578a610234565b8b5b73ffffffffffffffffffffffffffffffffffffffff881692919061063b565b8515610132575f816102655789610267565b885b61027090612698565b905061027b81610693565b61013273ffffffffffffffffffffffffffffffffffffffff8716826106c0565b3480156102a6575f80fd5b506102e76102b53660046127a2565b80516020818301810180515f8252928201919093012091525473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561031c575f80fd5b5061033061032b366004612812565b6106dd565b60408051928352602083019190915201610308565b610132610353366004612875565b610814565b348015610363575f80fd5b50610330610372366004612890565b610996565b6101326103853660046128f7565b610b42565b348015610395575f80fd5b506103a96103a4366004612948565b610c6d565b604051610308959493929190612a35565b6101326103c8366004612948565b610e9e565b6101326103db366004612812565b610fc9565b3480156103eb575f80fd5b506103ff6103fa366004612a91565b611134565b6040519015158152602001610308565b34801561041a575f80fd5b5061042e610429366004612948565b61119f565b6040805193845273ffffffffffffffffffffffffffffffffffffffff9283166020850152911690820152606001610308565b61013261046e366004612948565b6112c3565b34801561047e575f80fd5b506103ff6103fa366004612afc565b348015610498575f80fd5b506103a96104a7366004612812565b6115b7565b3480156104b7575f80fd5b506104cb6104c63660046127a2565b611719565b6040805173ffffffffffffffffffffffffffffffffffffffff948516815293909216602084015290820152606001610308565b5f808273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16101561053c57506001610540565b9192915b61054d8484610bb86119a2565b91508173ffffffffffffffffffffffffffffffffffffffff163b5f036105d65761057a84846101f46119a2565b91508173ffffffffffffffffffffffffffffffffffffffff163b5f036105d6576105a6848460646119a2565b91508173ffffffffffffffffffffffffffffffffffffffff163b5f036105d6576105d384846127106119a2565b91505b9250929050565b5f385f388473c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25af15033601452806034526fa9059cbb0000000000000000000000005f525f38604460105f73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25af1505f60345250565b60405181606052826040528360601b602c526f23b872dd000000000000000000000000600c5260205f6064601c5f895af13d1560015f5114171661068657637939f4245f526004601cfd5b5f60605260405250505050565b632e1a7d4d5f52806020525f386024601c5f73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25af15050565b5f385f3884865af16106d95763b12d13eb5f526004601cfd5b5050565b5f80806106f26106ed8587612b5c565b611a4f565b905073ffffffffffffffffffffffffffffffffffffffff8116610749575f8585604051610720929190612b98565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff1690505b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8216016107b8576040517f1e3382cb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6318160ddd5f526020806004601c845afa6107d1575f38fd5b60205192506107f58173ffffffffffffffffffffffffffffffffffffffff16611c9d565b61080090600a612cc5565b61080a9084612cd3565b9150509250929050565b5f61083c6108378373ffffffffffffffffffffffffffffffffffffffff16611cbf565b611ce5565b90505f6108616108378473ffffffffffffffffffffffffffffffffffffffff16611d6c565b9050825f836040516108739190612d0b565b908152604051908190036020018120805473ffffffffffffffffffffffffffffffffffffffff939093167fffffffffffffffffffffffff0000000000000000000000000000000000000000909316831790557fa4cea56cd77acc2291276688ddfb9e3144c5dc056ada99eed3cd0460fbeda175906108f2908590612d26565b60405180910390a2825f8260405161090a9190612d0b565b908152604051908190036020018120805473ffffffffffffffffffffffffffffffffffffffff939093167fffffffffffffffffffffffff0000000000000000000000000000000000000000909316831790557fa4cea56cd77acc2291276688ddfb9e3144c5dc056ada99eed3cd0460fbeda17590610989908490612d26565b60405180910390a2505050565b5f805f6109d787878080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061171992505050565b509150505f610a1a86868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611ce592505050565b90505f610a296106ed83612d38565b905073ffffffffffffffffffffffffffffffffffffffff8116610a80575f8787604051610a57929190612b98565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff1690505b73ffffffffffffffffffffffffffffffffffffffff811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1480610ad757610ad273ffffffffffffffffffffffffffffffffffffffff831685611d86565b610af0565b8373ffffffffffffffffffffffffffffffffffffffff16315b955080610b1b57610b168273ffffffffffffffffffffffffffffffffffffffff16611c9d565b610b1e565b60125b610b2990600a612cc5565b610b339087612cd3565b94505050505094509492505050565b3373da000000000000d2885f108500803dfbaab2f2aa14610b8f576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f610bce83838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611ce592505050565b9050835f82604051610be09190612d0b565b908152604051908190036020018120805473ffffffffffffffffffffffffffffffffffffffff939093167fffffffffffffffffffffffff0000000000000000000000000000000000000000909316831790557fa4cea56cd77acc2291276688ddfb9e3144c5dc056ada99eed3cd0460fbeda17590610c5f908490612d26565b60405180910390a250505050565b5f8080606080610c7f6106ed87612d38565b925073ffffffffffffffffffffffffffffffffffffffff8316610cd4575f86604051610cab9190612d0b565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff1692505b73ffffffffffffffffffffffffffffffffffffffff831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14610d0a89611719565b509650610d4390508882610d3c57610d378673ffffffffffffffffffffffffffffffffffffffff16611c9d565b611db9565b6012611db9565b945080610dec5760405173ffffffffffffffffffffffffffffffffffffffff8716602482015260448101869052606401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905292505b80610df75783610df9565b855b81610e04575f610e06565b855b84604051602401610e1993929190612d7a565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fb61d27f60000000000000000000000000000000000000000000000000000000017905295999498509296509094505050565b5f610eab6106ed83612d38565b905073ffffffffffffffffffffffffffffffffffffffff8116610f00575f82604051610ed79190612d0b565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff1690505b5f610f0a85611719565b509150507fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff831601610f7b57610f76610f59856012611db9565b73ffffffffffffffffffffffffffffffffffffffff8316906106c0565b610fc2565b610fc23382610fa387610d378773ffffffffffffffffffffffffffffffffffffffff16611c9d565b73ffffffffffffffffffffffffffffffffffffffff861692919061063b565b5050505050565b5f61100883838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611ce592505050565b90505f61101482611fa6565b9050807f73656e640000000000000000000000000000000000000000000000000000000014806110635750807f7472616e73666572000000000000000000000000000000000000000000000000145b1561108d575f805f61107485611fe6565b925092509250611085838383610e9e565b50505061112e565b807f737761700000000000000000000000000000000000000000000000000000000014806110da5750807f65786368616e6765000000000000000000000000000000000000000000000000145b156110fc575f805f6110eb856120d7565b9250925092506110858383836112c3565b6040517f1e3382cb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b5f8061114085856115b7565b9450505050508280606001906111569190612db7565b9050815114611168575f915050611198565b6111756060840184612db7565b604051611183929190612b98565b60405180910390208180519060200120149150505b9392505050565b5f80806111ae6106ed86612d38565b915073ffffffffffffffffffffffffffffffffffffffff8216611203575f856040516111da9190612d0b565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff1691505b61120f6106ed85612d38565b905073ffffffffffffffffffffffffffffffffffffffff8116611264575f8460405161123b9190612d0b565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff1690505b6112b88673ffffffffffffffffffffffffffffffffffffffff841673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14610d3c57610d378473ffffffffffffffffffffffffffffffffffffffff16611c9d565b925093509350939050565b5f6112d06106ed84612d38565b905073ffffffffffffffffffffffffffffffffffffffff8116611325575f836040516112fc9190612d0b565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff1690505b5f6113326106ed84612d38565b905073ffffffffffffffffffffffffffffffffffffffff8116611387575f8360405161135e9190612d0b565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff1690505b73ffffffffffffffffffffffffffffffffffffffff82811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee9081149183161481156113d95773c02aaa39b223fe8d0a0e5c4f27ead9083c756cc293505b80156113f75773c02aaa39b223fe8d0a0e5c4f27ead9083c756cc292505b5f6114208884610d3c57610d378773ffffffffffffffffffffffffffffffffffffffff16611c9d565b90507f8000000000000000000000000000000000000000000000000000000000000000811061147b576040517f35278d1200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8061148787876104fe565b915091508173ffffffffffffffffffffffffffffffffffffffff1663128acb0885156114b357306114b5565b335b8386856114d65773fffd8963efd1fc6a506488495d951d5263988d256114dd565b6401000276a45b6040518b151560f890811b60208301528b1515901b60218201527fffffffffffffffffffffffffffffffffffffffff00000000000000000000000033606090811b821660228401528f811b821660368401528e901b16604a820152605e016040516020818303038152906040526040518663ffffffff1660e01b815260040161156a959493929190612e18565b60408051808303815f875af1158015611585573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115a99190612e69565b505050505050505050505050565b5f805f6060805f6115fc88888080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611ce592505050565b90505f61160882611fa6565b9050807f73656e640000000000000000000000000000000000000000000000000000000014806116575750807f7472616e73666572000000000000000000000000000000000000000000000000145b1561168e575f805f61166885611fe6565b925092509250611679838383610c6d565b939d50919b5099509750955061170d92505050565b807f737761700000000000000000000000000000000000000000000000000000000014806116db5750807f65786368616e6765000000000000000000000000000000000000000000000000145b156110fc575f805f6116ec856120d7565b9250925092506116fd83838361119f565b9b50909950975061170d92505050565b50509295509295909350565b5f805f611744846040516020016117309190612e8b565b60405160208183030381529060405261215b565b6040517f02571be3000000000000000000000000000000000000000000000000000000008152600481018290529091506e0c2e074ec69a0dfb2997ba6c7d2e1e906302571be390602401602060405180830381865afa1580156117a9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117cd9190612ecb565b92507fffffffffffffffffffffffff2bbe94ec2d4c5654518532a293d44241da979bff73ffffffffffffffffffffffffffffffffffffffff84160161189a576040517f6352211e0000000000000000000000000000000000000000000000000000000081526004810182905273d4416b13d2b3a9abae7acd5d6c2bbdbe2568640190636352211e90602401602060405180830381865afa158015611873573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118979190612ecb565b92505b6040517f0178b8bf000000000000000000000000000000000000000000000000000000008152600481018290526e0c2e074ec69a0dfb2997ba6c7d2e1e90630178b8bf90602401602060405180830381865afa1580156118fc573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119209190612ecb565b73ffffffffffffffffffffffffffffffffffffffff16633b3b57de826040518263ffffffff1660e01b815260040161195a91815260200190565b602060405180830381865afa158015611975573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119999190612ecb565b91509193909250565b6040805173ffffffffffffffffffffffffffffffffffffffff808616602083015284169181019190915262ffffff821660608201525f90819060800160405160208183030381529060405280519060200120905060ff5f537fe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54603552731f98431c8ad98523631ae4a59f267346ea31f98460601b6001528060155260555f2091505f603552509392505050565b5f817f65746800000000000000000000000000000000000000000000000000000000001480611a9d5750817f6574686572000000000000000000000000000000000000000000000000000000145b15611abd575073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee919050565b817f757364630000000000000000000000000000000000000000000000000000000003611aff575073a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48919050565b817f757364740000000000000000000000000000000000000000000000000000000003611b41575073dac17f958d2ee523a2206206994597c13d831ec7919050565b817f646169000000000000000000000000000000000000000000000000000000000003611b835750736b175474e89094c44da98b954eedeac495271d0f919050565b817f6e616e690000000000000000000000000000000000000000000000000000000003611bbf57506d25824328358250920b271f348690919050565b817f776574680000000000000000000000000000000000000000000000000000000003611c01575073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2919050565b817f77627463000000000000000000000000000000000000000000000000000000001480611c4e5750817f6274630000000000000000000000000000000000000000000000000000000000145b80611c785750817f626974636f696e00000000000000000000000000000000000000000000000000145b15611c985750732260fac5e5542a773aa44fbcfedf7c193bc2c599919050565b919050565b63313ce56760049081525f908152611cb98282620186a0612362565b92915050565b6060611cb982611cd96306fdde0360049081525f90815290565b6103e8620186a0612381565b606081518015611d66576040516001939093019260200191506bffffffc000000000000000007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff825b81018581015160ff1683811c6020168118868301535080611d2e5750505060405191508082528060208301015f815260208101604052505b50919050565b6060611cb982611cd96395d89b4160049081525f90815290565b5f816014526f70a082310000000000000000000000005f5260208060246010865afa601f3d111660205102905092915050565b5f808084815b81518114611f83577f3000000000000000000000000000000000000000000000000000000000000000828281518110611dfa57611dfa612ee6565b01602001517fff000000000000000000000000000000000000000000000000000000000000001610801590611e8757507f3900000000000000000000000000000000000000000000000000000000000000828281518110611e5d57611e5d612ee6565b01602001517fff000000000000000000000000000000000000000000000000000000000000001611155b15611ed5576030828281518110611ea057611ea0612ee6565b602001015160f81c60f81b60f81c60ff1686600a02010394508315611ed0578260010192508560ff168311611f83575b611f7b565b818181518110611ee757611ee7612ee6565b6020910101517fff00000000000000000000000000000000000000000000000000000000000000167f2e00000000000000000000000000000000000000000000000000000000000000148015611f3b575083155b15611f495760019350611f7b565b6040517f312a9f5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600101611dbf565b508460ff16821015611f9d57818560ff1603600a0a840293505b50505092915050565b5f602082015f5b6020811015611fdf57808201515f1a60208103611fca5750611fdf565b6008820260f8031b9290921791600101611fad565b5050919050565b60608060605f612016857f200000000000000000000000000000000000000000000000000000000000000061242a565b9050805160040361207e578060018151811061203457612034612ee6565b60200260200101518160028151811061204f5761204f612ee6565b60200260200101518260038151811061206a5761206a612ee6565b6020026020010151935093509350506120d0565b80516005036110fc578060048151811061209a5761209a612ee6565b6020026020010151816001815181106120b5576120b5612ee6565b60200260200101518260028151811061206a5761206a612ee6565b9193909250565b60608060605f612107857f200000000000000000000000000000000000000000000000000000000000000061242a565b905080516005036110fc578060018151811061212557612125612ee6565b60200260200101518160028151811061214057612140612ee6565b60200260200101518260048151811061206a5761206a612ee6565b80515f90805b8115612325575f84600184038151811061217d5761217d612ee6565b01602001517fff000000000000000000000000000000000000000000000000000000000000001690507f2e0000000000000000000000000000000000000000000000000000000000000081900361221057828203602084870101208490604080516020810193909352820152606001604051602081830303815290604052805190602001209350600183039150506122fb565b7f80000000000000000000000000000000000000000000000000000000000000007fff0000000000000000000000000000000000000000000000000000000000000082161061225d575f80fd5b5f60018260f81c60ff168154811061227757612277612ee6565b5f91825260208083209082040154601f9091166101000a900460f81b915060ff1660f882901c036122a6575f80fd5b600160f882901c11156122f857808660018603815181106122c9576122c9612ee6565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505b50505b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90910190612161565b8181036020838601012083906040805160208101939093528201526060016040516020818303038152906040528051906020012092505050919050565b5f6020808451602086018786fa601f3d11166020510290509392505050565b606060205f8551602087018886fa15612422576040518060200160403d106123eb575f5160203d0381116123e957602081843e602081013d038351116123e957825186811181881802188084528060208301843e5f9201918252506020016040529050612422565b505b3d8581118187180218805f833e5f8183015350805b80515f1a1561241157600101612400565b90810382525f815260200160405290505b949350505050565b60608260015f5b825181146124a957847effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191683828151811061246e5761246e612ee6565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016036124a1578160010191505b600101612431565b508067ffffffffffffffff8111156124c3576124c36126ce565b6040519080825280602002602001820160405280156124f657816020015b60608152602001906001900390816124e15790505b5092505f805f5b8451811161266057845181148061256d5750867effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191685828151811061254457612544612ee6565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016145b15612658575f82820367ffffffffffffffff81111561258e5761258e6126ce565b6040519080825280601f01601f1916602001820160405280156125b8576020820181803683370190505b509050825b82811461262b578681815181106125d6576125d6612ee6565b602001015160f81c60f81b82858303815181106125f5576125f5612ee6565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053506001016125bd565b508087858151811061263f5761263f612ee6565b6020026020010181905250836001019350816001019250505b6001016124fd565b505050505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f7f800000000000000000000000000000000000000000000000000000000000000082036126c8576126c861266b565b505f0390565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f82601f83011261270a575f80fd5b813567ffffffffffffffff80821115612725576127256126ce565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190828211818310171561276b5761276b6126ce565b81604052838152866020858801011115612783575f80fd5b836020870160208301375f602085830101528094505050505092915050565b5f602082840312156127b2575f80fd5b813567ffffffffffffffff8111156127c8575f80fd5b612422848285016126fb565b5f8083601f8401126127e4575f80fd5b50813567ffffffffffffffff8111156127fb575f80fd5b6020830191508360208285010111156105d6575f80fd5b5f8060208385031215612823575f80fd5b823567ffffffffffffffff811115612839575f80fd5b612845858286016127d4565b90969095509350505050565b73ffffffffffffffffffffffffffffffffffffffff81168114612872575f80fd5b50565b5f60208284031215612885575f80fd5b813561119881612851565b5f805f80604085870312156128a3575f80fd5b843567ffffffffffffffff808211156128ba575f80fd5b6128c6888389016127d4565b909650945060208701359150808211156128de575f80fd5b506128eb878288016127d4565b95989497509550505050565b5f805f60408486031215612909575f80fd5b833561291481612851565b9250602084013567ffffffffffffffff81111561292f575f80fd5b61293b868287016127d4565b9497909650939450505050565b5f805f6060848603121561295a575f80fd5b833567ffffffffffffffff80821115612971575f80fd5b61297d878388016126fb565b94506020860135915080821115612992575f80fd5b61299e878388016126fb565b935060408601359150808211156129b3575f80fd5b506129c0868287016126fb565b9150509250925092565b5f5b838110156129e45781810151838201526020016129cc565b50505f910152565b5f8151808452612a038160208601602086016129ca565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b5f73ffffffffffffffffffffffffffffffffffffffff808816835286602084015280861660408401525060a06060830152612a7360a08301856129ec565b8281036080840152612a8581856129ec565b98975050505050505050565b5f805f60408486031215612aa3575f80fd5b833567ffffffffffffffff80821115612aba575f80fd5b612ac6878388016127d4565b90955093506020860135915080821115612ade575f80fd5b5084016101208187031215612af1575f80fd5b809150509250925092565b5f805f60408486031215612b0e575f80fd5b833567ffffffffffffffff80821115612b25575f80fd5b612b31878388016127d4565b90955093506020860135915080821115612b49575f80fd5b5084016101608187031215612af1575f80fd5b80356020831015611cb9577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602084900360031b1b1692915050565b818382375f9101908152919050565b600181815b80851115612c0057817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115612be657612be661266b565b80851615612bf357918102915b93841c9390800290612bac565b509250929050565b5f82612c1657506001611cb9565b81612c2257505f611cb9565b8160018114612c385760028114612c4257612c5e565b6001915050611cb9565b60ff841115612c5357612c5361266b565b50506001821b611cb9565b5060208310610133831016604e8410600b8410161715612c81575081810a611cb9565b612c8b8383612ba7565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115612cbd57612cbd61266b565b029392505050565b5f61119860ff841683612c08565b5f82612d06577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b5f8251612d1c8184602087016129ca565b9190910192915050565b602081525f61119860208301846129ec565b80516020808301519190811015611d66577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60209190910360031b1b16919050565b73ffffffffffffffffffffffffffffffffffffffff84168152826020820152606060408201525f612dae60608301846129ec565b95945050505050565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612dea575f80fd5b83018035915067ffffffffffffffff821115612e04575f80fd5b6020019150368190038213156105d6575f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff8088168352861515602084015285604084015280851660608401525060a06080830152612e5e60a08301846129ec565b979650505050505050565b5f8060408385031215612e7a575f80fd5b505080516020909101519092909150565b5f8251612e9c8184602087016129ca565b7f2e65746800000000000000000000000000000000000000000000000000000000920191825250600401919050565b5f60208284031215612edb575f80fd5b815161119881612851565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffdfea264697066735822122038af376b35a6d498afa7275e4ae0cf9671901c58b82f681a2aa5029bb12be19b64736f6c634300081800332d00020101000a010700016101620163016401650166016701680169016a016b016c016d016e016f0170017101720173017401750176017701780179017a06001a010500
Deployed Bytecode
0x6080604052600436106100e0575f3560e01c80635fcc45001161007e578063b695b01611610058578063b695b01614610460578063bf0213cd14610473578063bfe686761461048d578063c47d04e2146104ac57610134565b80635fcc4500146103cd5780638b9c93d4146103e0578063aa3aa1421461040f57610134565b80632d8f63db116100ba5780632d8f63db146103585780633121db1c146103775780633e7043851461038a5780635615264d146103ba57610134565b806304c2320b1461029b578063109fe41f14610311578063258cbaf11461034557610134565b36610134573373c02aaa39b223fe8d0a0e5c4f27ead9083c756cc214610132576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b005b6004356024356084355f90811a90608535811a90608635606090811c91609a35821c9160ae35901c90871380159061016c57505f8613155b156101a3576040517f1115766700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f806101af84846104fe565b90925090503373ffffffffffffffffffffffffffffffffffffffff831614610203576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b86156102225761021d8161021757886105dd565b896105dd565b610253565b610253853383610232578a610234565b8b5b73ffffffffffffffffffffffffffffffffffffffff881692919061063b565b8515610132575f816102655789610267565b885b61027090612698565b905061027b81610693565b61013273ffffffffffffffffffffffffffffffffffffffff8716826106c0565b3480156102a6575f80fd5b506102e76102b53660046127a2565b80516020818301810180515f8252928201919093012091525473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561031c575f80fd5b5061033061032b366004612812565b6106dd565b60408051928352602083019190915201610308565b610132610353366004612875565b610814565b348015610363575f80fd5b50610330610372366004612890565b610996565b6101326103853660046128f7565b610b42565b348015610395575f80fd5b506103a96103a4366004612948565b610c6d565b604051610308959493929190612a35565b6101326103c8366004612948565b610e9e565b6101326103db366004612812565b610fc9565b3480156103eb575f80fd5b506103ff6103fa366004612a91565b611134565b6040519015158152602001610308565b34801561041a575f80fd5b5061042e610429366004612948565b61119f565b6040805193845273ffffffffffffffffffffffffffffffffffffffff9283166020850152911690820152606001610308565b61013261046e366004612948565b6112c3565b34801561047e575f80fd5b506103ff6103fa366004612afc565b348015610498575f80fd5b506103a96104a7366004612812565b6115b7565b3480156104b7575f80fd5b506104cb6104c63660046127a2565b611719565b6040805173ffffffffffffffffffffffffffffffffffffffff948516815293909216602084015290820152606001610308565b5f808273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16101561053c57506001610540565b9192915b61054d8484610bb86119a2565b91508173ffffffffffffffffffffffffffffffffffffffff163b5f036105d65761057a84846101f46119a2565b91508173ffffffffffffffffffffffffffffffffffffffff163b5f036105d6576105a6848460646119a2565b91508173ffffffffffffffffffffffffffffffffffffffff163b5f036105d6576105d384846127106119a2565b91505b9250929050565b5f385f388473c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25af15033601452806034526fa9059cbb0000000000000000000000005f525f38604460105f73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25af1505f60345250565b60405181606052826040528360601b602c526f23b872dd000000000000000000000000600c5260205f6064601c5f895af13d1560015f5114171661068657637939f4245f526004601cfd5b5f60605260405250505050565b632e1a7d4d5f52806020525f386024601c5f73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25af15050565b5f385f3884865af16106d95763b12d13eb5f526004601cfd5b5050565b5f80806106f26106ed8587612b5c565b611a4f565b905073ffffffffffffffffffffffffffffffffffffffff8116610749575f8585604051610720929190612b98565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff1690505b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8216016107b8576040517f1e3382cb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6318160ddd5f526020806004601c845afa6107d1575f38fd5b60205192506107f58173ffffffffffffffffffffffffffffffffffffffff16611c9d565b61080090600a612cc5565b61080a9084612cd3565b9150509250929050565b5f61083c6108378373ffffffffffffffffffffffffffffffffffffffff16611cbf565b611ce5565b90505f6108616108378473ffffffffffffffffffffffffffffffffffffffff16611d6c565b9050825f836040516108739190612d0b565b908152604051908190036020018120805473ffffffffffffffffffffffffffffffffffffffff939093167fffffffffffffffffffffffff0000000000000000000000000000000000000000909316831790557fa4cea56cd77acc2291276688ddfb9e3144c5dc056ada99eed3cd0460fbeda175906108f2908590612d26565b60405180910390a2825f8260405161090a9190612d0b565b908152604051908190036020018120805473ffffffffffffffffffffffffffffffffffffffff939093167fffffffffffffffffffffffff0000000000000000000000000000000000000000909316831790557fa4cea56cd77acc2291276688ddfb9e3144c5dc056ada99eed3cd0460fbeda17590610989908490612d26565b60405180910390a2505050565b5f805f6109d787878080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061171992505050565b509150505f610a1a86868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611ce592505050565b90505f610a296106ed83612d38565b905073ffffffffffffffffffffffffffffffffffffffff8116610a80575f8787604051610a57929190612b98565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff1690505b73ffffffffffffffffffffffffffffffffffffffff811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1480610ad757610ad273ffffffffffffffffffffffffffffffffffffffff831685611d86565b610af0565b8373ffffffffffffffffffffffffffffffffffffffff16315b955080610b1b57610b168273ffffffffffffffffffffffffffffffffffffffff16611c9d565b610b1e565b60125b610b2990600a612cc5565b610b339087612cd3565b94505050505094509492505050565b3373da000000000000d2885f108500803dfbaab2f2aa14610b8f576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f610bce83838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611ce592505050565b9050835f82604051610be09190612d0b565b908152604051908190036020018120805473ffffffffffffffffffffffffffffffffffffffff939093167fffffffffffffffffffffffff0000000000000000000000000000000000000000909316831790557fa4cea56cd77acc2291276688ddfb9e3144c5dc056ada99eed3cd0460fbeda17590610c5f908490612d26565b60405180910390a250505050565b5f8080606080610c7f6106ed87612d38565b925073ffffffffffffffffffffffffffffffffffffffff8316610cd4575f86604051610cab9190612d0b565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff1692505b73ffffffffffffffffffffffffffffffffffffffff831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14610d0a89611719565b509650610d4390508882610d3c57610d378673ffffffffffffffffffffffffffffffffffffffff16611c9d565b611db9565b6012611db9565b945080610dec5760405173ffffffffffffffffffffffffffffffffffffffff8716602482015260448101869052606401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905292505b80610df75783610df9565b855b81610e04575f610e06565b855b84604051602401610e1993929190612d7a565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fb61d27f60000000000000000000000000000000000000000000000000000000017905295999498509296509094505050565b5f610eab6106ed83612d38565b905073ffffffffffffffffffffffffffffffffffffffff8116610f00575f82604051610ed79190612d0b565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff1690505b5f610f0a85611719565b509150507fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff831601610f7b57610f76610f59856012611db9565b73ffffffffffffffffffffffffffffffffffffffff8316906106c0565b610fc2565b610fc23382610fa387610d378773ffffffffffffffffffffffffffffffffffffffff16611c9d565b73ffffffffffffffffffffffffffffffffffffffff861692919061063b565b5050505050565b5f61100883838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611ce592505050565b90505f61101482611fa6565b9050807f73656e640000000000000000000000000000000000000000000000000000000014806110635750807f7472616e73666572000000000000000000000000000000000000000000000000145b1561108d575f805f61107485611fe6565b925092509250611085838383610e9e565b50505061112e565b807f737761700000000000000000000000000000000000000000000000000000000014806110da5750807f65786368616e6765000000000000000000000000000000000000000000000000145b156110fc575f805f6110eb856120d7565b9250925092506110858383836112c3565b6040517f1e3382cb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b5f8061114085856115b7565b9450505050508280606001906111569190612db7565b9050815114611168575f915050611198565b6111756060840184612db7565b604051611183929190612b98565b60405180910390208180519060200120149150505b9392505050565b5f80806111ae6106ed86612d38565b915073ffffffffffffffffffffffffffffffffffffffff8216611203575f856040516111da9190612d0b565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff1691505b61120f6106ed85612d38565b905073ffffffffffffffffffffffffffffffffffffffff8116611264575f8460405161123b9190612d0b565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff1690505b6112b88673ffffffffffffffffffffffffffffffffffffffff841673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14610d3c57610d378473ffffffffffffffffffffffffffffffffffffffff16611c9d565b925093509350939050565b5f6112d06106ed84612d38565b905073ffffffffffffffffffffffffffffffffffffffff8116611325575f836040516112fc9190612d0b565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff1690505b5f6113326106ed84612d38565b905073ffffffffffffffffffffffffffffffffffffffff8116611387575f8360405161135e9190612d0b565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff1690505b73ffffffffffffffffffffffffffffffffffffffff82811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee9081149183161481156113d95773c02aaa39b223fe8d0a0e5c4f27ead9083c756cc293505b80156113f75773c02aaa39b223fe8d0a0e5c4f27ead9083c756cc292505b5f6114208884610d3c57610d378773ffffffffffffffffffffffffffffffffffffffff16611c9d565b90507f8000000000000000000000000000000000000000000000000000000000000000811061147b576040517f35278d1200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8061148787876104fe565b915091508173ffffffffffffffffffffffffffffffffffffffff1663128acb0885156114b357306114b5565b335b8386856114d65773fffd8963efd1fc6a506488495d951d5263988d256114dd565b6401000276a45b6040518b151560f890811b60208301528b1515901b60218201527fffffffffffffffffffffffffffffffffffffffff00000000000000000000000033606090811b821660228401528f811b821660368401528e901b16604a820152605e016040516020818303038152906040526040518663ffffffff1660e01b815260040161156a959493929190612e18565b60408051808303815f875af1158015611585573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115a99190612e69565b505050505050505050505050565b5f805f6060805f6115fc88888080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611ce592505050565b90505f61160882611fa6565b9050807f73656e640000000000000000000000000000000000000000000000000000000014806116575750807f7472616e73666572000000000000000000000000000000000000000000000000145b1561168e575f805f61166885611fe6565b925092509250611679838383610c6d565b939d50919b5099509750955061170d92505050565b807f737761700000000000000000000000000000000000000000000000000000000014806116db5750807f65786368616e6765000000000000000000000000000000000000000000000000145b156110fc575f805f6116ec856120d7565b9250925092506116fd83838361119f565b9b50909950975061170d92505050565b50509295509295909350565b5f805f611744846040516020016117309190612e8b565b60405160208183030381529060405261215b565b6040517f02571be3000000000000000000000000000000000000000000000000000000008152600481018290529091506e0c2e074ec69a0dfb2997ba6c7d2e1e906302571be390602401602060405180830381865afa1580156117a9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117cd9190612ecb565b92507fffffffffffffffffffffffff2bbe94ec2d4c5654518532a293d44241da979bff73ffffffffffffffffffffffffffffffffffffffff84160161189a576040517f6352211e0000000000000000000000000000000000000000000000000000000081526004810182905273d4416b13d2b3a9abae7acd5d6c2bbdbe2568640190636352211e90602401602060405180830381865afa158015611873573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118979190612ecb565b92505b6040517f0178b8bf000000000000000000000000000000000000000000000000000000008152600481018290526e0c2e074ec69a0dfb2997ba6c7d2e1e90630178b8bf90602401602060405180830381865afa1580156118fc573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119209190612ecb565b73ffffffffffffffffffffffffffffffffffffffff16633b3b57de826040518263ffffffff1660e01b815260040161195a91815260200190565b602060405180830381865afa158015611975573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119999190612ecb565b91509193909250565b6040805173ffffffffffffffffffffffffffffffffffffffff808616602083015284169181019190915262ffffff821660608201525f90819060800160405160208183030381529060405280519060200120905060ff5f537fe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54603552731f98431c8ad98523631ae4a59f267346ea31f98460601b6001528060155260555f2091505f603552509392505050565b5f817f65746800000000000000000000000000000000000000000000000000000000001480611a9d5750817f6574686572000000000000000000000000000000000000000000000000000000145b15611abd575073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee919050565b817f757364630000000000000000000000000000000000000000000000000000000003611aff575073a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48919050565b817f757364740000000000000000000000000000000000000000000000000000000003611b41575073dac17f958d2ee523a2206206994597c13d831ec7919050565b817f646169000000000000000000000000000000000000000000000000000000000003611b835750736b175474e89094c44da98b954eedeac495271d0f919050565b817f6e616e690000000000000000000000000000000000000000000000000000000003611bbf57506d25824328358250920b271f348690919050565b817f776574680000000000000000000000000000000000000000000000000000000003611c01575073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2919050565b817f77627463000000000000000000000000000000000000000000000000000000001480611c4e5750817f6274630000000000000000000000000000000000000000000000000000000000145b80611c785750817f626974636f696e00000000000000000000000000000000000000000000000000145b15611c985750732260fac5e5542a773aa44fbcfedf7c193bc2c599919050565b919050565b63313ce56760049081525f908152611cb98282620186a0612362565b92915050565b6060611cb982611cd96306fdde0360049081525f90815290565b6103e8620186a0612381565b606081518015611d66576040516001939093019260200191506bffffffc000000000000000007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff825b81018581015160ff1683811c6020168118868301535080611d2e5750505060405191508082528060208301015f815260208101604052505b50919050565b6060611cb982611cd96395d89b4160049081525f90815290565b5f816014526f70a082310000000000000000000000005f5260208060246010865afa601f3d111660205102905092915050565b5f808084815b81518114611f83577f3000000000000000000000000000000000000000000000000000000000000000828281518110611dfa57611dfa612ee6565b01602001517fff000000000000000000000000000000000000000000000000000000000000001610801590611e8757507f3900000000000000000000000000000000000000000000000000000000000000828281518110611e5d57611e5d612ee6565b01602001517fff000000000000000000000000000000000000000000000000000000000000001611155b15611ed5576030828281518110611ea057611ea0612ee6565b602001015160f81c60f81b60f81c60ff1686600a02010394508315611ed0578260010192508560ff168311611f83575b611f7b565b818181518110611ee757611ee7612ee6565b6020910101517fff00000000000000000000000000000000000000000000000000000000000000167f2e00000000000000000000000000000000000000000000000000000000000000148015611f3b575083155b15611f495760019350611f7b565b6040517f312a9f5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600101611dbf565b508460ff16821015611f9d57818560ff1603600a0a840293505b50505092915050565b5f602082015f5b6020811015611fdf57808201515f1a60208103611fca5750611fdf565b6008820260f8031b9290921791600101611fad565b5050919050565b60608060605f612016857f200000000000000000000000000000000000000000000000000000000000000061242a565b9050805160040361207e578060018151811061203457612034612ee6565b60200260200101518160028151811061204f5761204f612ee6565b60200260200101518260038151811061206a5761206a612ee6565b6020026020010151935093509350506120d0565b80516005036110fc578060048151811061209a5761209a612ee6565b6020026020010151816001815181106120b5576120b5612ee6565b60200260200101518260028151811061206a5761206a612ee6565b9193909250565b60608060605f612107857f200000000000000000000000000000000000000000000000000000000000000061242a565b905080516005036110fc578060018151811061212557612125612ee6565b60200260200101518160028151811061214057612140612ee6565b60200260200101518260048151811061206a5761206a612ee6565b80515f90805b8115612325575f84600184038151811061217d5761217d612ee6565b01602001517fff000000000000000000000000000000000000000000000000000000000000001690507f2e0000000000000000000000000000000000000000000000000000000000000081900361221057828203602084870101208490604080516020810193909352820152606001604051602081830303815290604052805190602001209350600183039150506122fb565b7f80000000000000000000000000000000000000000000000000000000000000007fff0000000000000000000000000000000000000000000000000000000000000082161061225d575f80fd5b5f60018260f81c60ff168154811061227757612277612ee6565b5f91825260208083209082040154601f9091166101000a900460f81b915060ff1660f882901c036122a6575f80fd5b600160f882901c11156122f857808660018603815181106122c9576122c9612ee6565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505b50505b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90910190612161565b8181036020838601012083906040805160208101939093528201526060016040516020818303038152906040528051906020012092505050919050565b5f6020808451602086018786fa601f3d11166020510290509392505050565b606060205f8551602087018886fa15612422576040518060200160403d106123eb575f5160203d0381116123e957602081843e602081013d038351116123e957825186811181881802188084528060208301843e5f9201918252506020016040529050612422565b505b3d8581118187180218805f833e5f8183015350805b80515f1a1561241157600101612400565b90810382525f815260200160405290505b949350505050565b60608260015f5b825181146124a957847effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191683828151811061246e5761246e612ee6565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016036124a1578160010191505b600101612431565b508067ffffffffffffffff8111156124c3576124c36126ce565b6040519080825280602002602001820160405280156124f657816020015b60608152602001906001900390816124e15790505b5092505f805f5b8451811161266057845181148061256d5750867effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191685828151811061254457612544612ee6565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016145b15612658575f82820367ffffffffffffffff81111561258e5761258e6126ce565b6040519080825280601f01601f1916602001820160405280156125b8576020820181803683370190505b509050825b82811461262b578681815181106125d6576125d6612ee6565b602001015160f81c60f81b82858303815181106125f5576125f5612ee6565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053506001016125bd565b508087858151811061263f5761263f612ee6565b6020026020010181905250836001019350816001019250505b6001016124fd565b505050505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f7f800000000000000000000000000000000000000000000000000000000000000082036126c8576126c861266b565b505f0390565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f82601f83011261270a575f80fd5b813567ffffffffffffffff80821115612725576127256126ce565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190828211818310171561276b5761276b6126ce565b81604052838152866020858801011115612783575f80fd5b836020870160208301375f602085830101528094505050505092915050565b5f602082840312156127b2575f80fd5b813567ffffffffffffffff8111156127c8575f80fd5b612422848285016126fb565b5f8083601f8401126127e4575f80fd5b50813567ffffffffffffffff8111156127fb575f80fd5b6020830191508360208285010111156105d6575f80fd5b5f8060208385031215612823575f80fd5b823567ffffffffffffffff811115612839575f80fd5b612845858286016127d4565b90969095509350505050565b73ffffffffffffffffffffffffffffffffffffffff81168114612872575f80fd5b50565b5f60208284031215612885575f80fd5b813561119881612851565b5f805f80604085870312156128a3575f80fd5b843567ffffffffffffffff808211156128ba575f80fd5b6128c6888389016127d4565b909650945060208701359150808211156128de575f80fd5b506128eb878288016127d4565b95989497509550505050565b5f805f60408486031215612909575f80fd5b833561291481612851565b9250602084013567ffffffffffffffff81111561292f575f80fd5b61293b868287016127d4565b9497909650939450505050565b5f805f6060848603121561295a575f80fd5b833567ffffffffffffffff80821115612971575f80fd5b61297d878388016126fb565b94506020860135915080821115612992575f80fd5b61299e878388016126fb565b935060408601359150808211156129b3575f80fd5b506129c0868287016126fb565b9150509250925092565b5f5b838110156129e45781810151838201526020016129cc565b50505f910152565b5f8151808452612a038160208601602086016129ca565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b5f73ffffffffffffffffffffffffffffffffffffffff808816835286602084015280861660408401525060a06060830152612a7360a08301856129ec565b8281036080840152612a8581856129ec565b98975050505050505050565b5f805f60408486031215612aa3575f80fd5b833567ffffffffffffffff80821115612aba575f80fd5b612ac6878388016127d4565b90955093506020860135915080821115612ade575f80fd5b5084016101208187031215612af1575f80fd5b809150509250925092565b5f805f60408486031215612b0e575f80fd5b833567ffffffffffffffff80821115612b25575f80fd5b612b31878388016127d4565b90955093506020860135915080821115612b49575f80fd5b5084016101608187031215612af1575f80fd5b80356020831015611cb9577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602084900360031b1b1692915050565b818382375f9101908152919050565b600181815b80851115612c0057817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115612be657612be661266b565b80851615612bf357918102915b93841c9390800290612bac565b509250929050565b5f82612c1657506001611cb9565b81612c2257505f611cb9565b8160018114612c385760028114612c4257612c5e565b6001915050611cb9565b60ff841115612c5357612c5361266b565b50506001821b611cb9565b5060208310610133831016604e8410600b8410161715612c81575081810a611cb9565b612c8b8383612ba7565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115612cbd57612cbd61266b565b029392505050565b5f61119860ff841683612c08565b5f82612d06577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b5f8251612d1c8184602087016129ca565b9190910192915050565b602081525f61119860208301846129ec565b80516020808301519190811015611d66577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60209190910360031b1b16919050565b73ffffffffffffffffffffffffffffffffffffffff84168152826020820152606060408201525f612dae60608301846129ec565b95945050505050565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612dea575f80fd5b83018035915067ffffffffffffffff821115612e04575f80fd5b6020019150368190038213156105d6575f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff8088168352861515602084015285604084015280851660608401525060a06080830152612e5e60a08301846129ec565b979650505050505050565b5f8060408385031215612e7a575f80fd5b505080516020909101519092909150565b5f8251612e9c8184602087016129ca565b7f2e65746800000000000000000000000000000000000000000000000000000000920191825250600401919050565b5f60208284031215612edb575f80fd5b815161119881612851565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffdfea264697066735822122038af376b35a6d498afa7275e4ae0cf9671901c58b82f681a2aa5029bb12be19b64736f6c63430008180033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.