ZeusStateViewV2

Description:

Decentralized Finance (DeFi) protocol contract providing Liquidity, Factory functionality.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "src/ZeusStateViewV2.sol": {
      "content": "// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import {MetadataReaderLib} from "./lib/MetadataReader.sol";

/*
ZZZZZZZZZZZZZZZZZZZ
Z:::::::::::::::::Z
Z:::::::::::::::::Z
Z:::ZZZZZZZZ:::::Z
ZZZZZ     Z:::::Z      eeeeeeeeeeee    uuuuuu    uuuuuu      ssssssssss
        Z:::::Z      ee::::::::::::ee  u::::u    u::::u    ss::::::::::s
       Z:::::Z      e::::::eeeee:::::eeu::::u    u::::u  ss:::::::::::::s
      Z:::::Z      e::::::e     e:::::eu::::u    u::::u  s::::::ssss:::::s
     Z:::::Z       e:::::::eeeee::::::eu::::u    u::::u   s:::::s  ssssss
    Z:::::Z        e:::::::::::::::::e u::::u    u::::u     s::::::s
   Z:::::Z         e::::::eeeeeeeeeee  u::::u    u::::u        s::::::s
ZZZ:::::Z     ZZZZZe:::::::e           u:::::uuuu:::::u  ssssss   s:::::s
Z::::::ZZZZZZZZ:::Ze::::::::e          u:::::::::::::::uus:::::ssss::::::s
Z:::::::::::::::::Z e::::::::eeeeeeee   u:::::::::::::::us::::::::::::::s
Z:::::::::::::::::Z  ee:::::::::::::e    uu::::::::uu:::u s:::::::::::ss
ZZZZZZZZZZZZZZZZZZZ    eeeeeeeeeeeeee      uuuuuuuu  uuuu  sssssssssss

State view contract for Zeus
Github: https://github.com/greekfetacheese/zeus-stateview
*/

contract ZeusStateViewV2 {
    uint24 FEE_LOWEST = 100;
    uint24 FEE_LOW = 500;
    uint24 FEE_MEDIUM = 3000;
    uint24 FEE_HIGH = 10000;

    uint24[] feeTiers = [FEE_LOWEST, FEE_LOW, FEE_MEDIUM, FEE_HIGH];

    /// @notice Response of the `getETHBalance` function
    struct ETHBalance {
        address owner;
        uint256 balance;
    }

    /// @notice Response of the `getERC20Balance` function
    struct ERC20Balance {
        address token;
        uint256 balance;
    }

    /// @notice Response of the `getERC20Info` function
    struct ERC20Info {
        address addr;
        string symbol;
        string name;
        uint256 totalSupply;
        uint8 decimals;
    }

    /// @notice Response of the `getV2Pools` function
    struct V2Pool {
        address addr;
        address tokenA;
        address tokenB;
    }

    /// @notice Response of the `getV3Pools` function
    struct V3Pool {
        address addr;
        address tokenA;
        address tokenB;
        uint24 fee;
    }

    /// @notice Response of the `getV2Reserves` function
    struct V2PoolReserves {
        address pool;
        uint112 reserve0;
        uint112 reserve1;
        uint32 blockTimestampLast;
    }

    /// @notice Response of the `getV3PoolState` function
    struct V3PoolData {
        address pool;
        uint256 tokenABalance;
        uint256 tokenBBalance;
        uint256 feeGrowthGlobal0X128;
        uint256 feeGrowthGlobal1X128;
        uint256 feeGrowthOutside0X128;
        uint256 feeGrowthOutside1X128;
        uint128 liquidity;
        uint160 sqrtPriceX96;
        int24 tick;
        uint256 tickBitmap;
        int16 wordPos;
        int128 liquidityNet;
        uint128 liquidityGross;
        bool initialized;
    }

    /// @notice Response of the `getV4PoolState` function
    struct V4PoolData {
        bytes32 pool;
        uint256 feeGrowthGlobal0;
        uint256 feeGrowthGlobal1;
        uint256 feeGrowthOutside0X128;
        uint256 feeGrowthOutside1X128;
        uint128 liquidity;
        uint160 sqrtPriceX96;
        int24 tick;
        uint256 tickBitmap;
        int16 wordPos;
        int128 liquidityNet;
        uint128 liquidityGross;
    }

    /// @notice Response of the `getPoolsState` function
    struct PoolsState {
        V2PoolReserves[] v2Reserves;
        V3PoolData[] v3PoolsData;
        V4PoolData[] v4PoolsData;
    }

    /// @notice Response of the `getPools` function
    struct Pools {
        V2Pool[] v2Pools;
        V3Pool[] v3Pools;
        bytes32[] v4Pools;
    }

    /// @notice Argument for the `getV4PoolState` function
    struct V4Pool {
        bytes32 pool;
        int24 tickSpacing;
    }

    /// @notice Query the ETH balance of multiple addresses
    function getETHBalance(address[] memory owners) external view returns (ETHBalance[] memory) {
        ETHBalance[] memory balances = new ETHBalance[](owners.length);
        for (uint256 i = 0; i < owners.length; i++) {
            balances[i] = ETHBalance(owners[i], owners[i].balance);
        }
        return balances;
    }

    /// @notice Query the balance of multiple ERC20 tokens for a given owner
    function getERC20Balance(address[] memory tokens, address owner) external view returns (ERC20Balance[] memory) {
        ERC20Balance[] memory balances = new ERC20Balance[](tokens.length);
        for (uint256 i = 0; i < tokens.length; i++) {
            balances[i] = ERC20Balance(tokens[i], balanceOf(tokens[i], owner));
        }
        return balances;
    }

    /// @notice Get the metadata for an ERC20 token
    function getERC20Info(address token) external view returns (ERC20Info memory) {
        return _getERC20Info(token);
    }

    /// @notice Get the metadata for multiple ERC20 tokens
    function getERC20InfoBatch(address[] memory tokens) external view returns (ERC20Info[] memory) {
        ERC20Info[] memory info = new ERC20Info[](tokens.length);
        for (uint256 i = 0; i < tokens.length; i++) {
            info[i] = _getERC20Info(tokens[i]);
        }
        return info;
    }

    /// @notice Query the state of multiple V2/V3/V4 pools
    function getPoolsState(
        address[] memory v2pools,
        V3Pool[] memory v3pools,
        V4Pool[] memory v4pools,
        address stateView
    ) external view returns (PoolsState memory) {
        PoolsState memory poolsState = PoolsState({
            v2Reserves: _getV2Reserves(v2pools),
            v3PoolsData: _getV3PoolState(v3pools),
            v4PoolsData: _getV4PoolState(v4pools, stateView)
        });
        return poolsState;
    }

    /// @notice Get all possible V2/V3 pools based on token pair and all fee tiers
    /// @notice For V4 pools, it will validate the id's by checking the liquidity
    function getPools(
        address v2factory,
        address v3factory,
        address stateView,
        bytes32[] memory v4pools,
        address[] memory baseTokens,
        address quoteToken
    ) external view returns (Pools memory) {
        V2Pool[] memory v2Pools = new V2Pool[](baseTokens.length);

        for (uint256 i = 0; i < baseTokens.length; i++) {
            V2Pool memory pool = _getV2Pool(v2factory, baseTokens[i], quoteToken);
            if (pool.addr != address(0)) {
                v2Pools[i] = pool;
            }
        }

        V3Pool[] memory v3Pools = new V3Pool[](baseTokens.length * feeTiers.length);
        for (uint256 i = 0; i < baseTokens.length; i++) {
            v3Pools = _getV3Pools(v3factory, baseTokens[i], quoteToken);
        }

        bytes32[] memory v4Pools = _validateV4Pools(stateView, v4pools);

        return Pools({v2Pools: v2Pools, v3Pools: v3Pools, v4Pools: v4Pools});
    }

    /// @notice Get the V2 pool based on token pair
    function getV2Pool(address factory, address tokenA, address tokenB) external view returns (V2Pool memory) {
        return _getV2Pool(factory, tokenA, tokenB);
    }

    /// @notice Get all the possible V3 pools based on token pair and all fee tiers
    function getV3Pools(address factory, address tokenA, address tokenB) external view returns (V3Pool[] memory) {
        return _getV3Pools(factory, tokenA, tokenB);
    }

    /// @notice Validate the given V4 Pools
    /// @notice Returns an array of valid pools
    function validateV4Pools(address stateView, bytes32[] memory pools) external view returns (bytes32[] memory) {
        return _validateV4Pools(stateView, pools);
    }

    /// @notice Query the reserves of multiple V2 pools
    function getV2Reserves(address[] memory pools) external view returns (V2PoolReserves[] memory) {
        return _getV2Reserves(pools);
    }

    /// @notice Query the state of multiple V3 pools
    function getV3PoolState(V3Pool[] memory pools) external view returns (V3PoolData[] memory) {
        return _getV3PoolState(pools);
    }

    /// @notice Query the state of multiple V4 pools
    function getV4PoolState(V4Pool[] memory pools, address stateView) external view returns (V4PoolData[] memory) {
        return _getV4PoolState(pools, stateView);
    }

    // *****************************************************************************
    // *                                                                           *
    // *                               Helpers                                     *
    // *                                                                           *
    // *****************************************************************************

    function _getERC20Info(address token) internal view returns (ERC20Info memory) {
        string memory name = MetadataReaderLib.readName(token);
        string memory symbol = MetadataReaderLib.readSymbol(token);
        uint8 decimals = MetadataReaderLib.readDecimals(token);
        uint256 totalSupply = 0;
        try IERC20(token).totalSupply() returns (uint256 _supply) {
            totalSupply = _supply;
        } catch {}
        return ERC20Info(token, symbol, name, totalSupply, decimals);
    }

    function _getV2Pool(address factory, address tokenA, address tokenB) internal view returns (V2Pool memory) {
        address poolAddr = IV2Factory(factory).getPair(tokenA, tokenB);
        V2Pool memory v2Pool = V2Pool({addr: poolAddr, tokenA: tokenA, tokenB: tokenB});
        return v2Pool;
    }

    function _getV3Pools(address factory, address tokenA, address tokenB) internal view returns (V3Pool[] memory) {
        V3Pool[] memory pools = new V3Pool[](feeTiers.length);
        for (uint256 i = 0; i < feeTiers.length; i++) {
            address poolAddr = IV3Factory(factory).getPool(tokenA, tokenB, feeTiers[i]);
            if (poolAddr != address(0)) {
                V3Pool memory v3Pool = V3Pool({addr: poolAddr, tokenA: tokenA, tokenB: tokenB, fee: feeTiers[i]});
                pools[i] = v3Pool;
            }
        }
        return pools;
    }

    function _validateV4Pools(address stateView, bytes32[] memory pools) internal view returns (bytes32[] memory) {
        IStateView stateViewContract = IStateView(stateView);
        bytes32[] memory validPools = new bytes32[](pools.length);

        for (uint256 i = 0; i < pools.length; i++) {
            uint128 liquidity = stateViewContract.getLiquidity(pools[i]);

            if (liquidity > 0) {
                validPools[i] = pools[i];
            }
        }
        return validPools;
    }

    function _getV2Reserves(address[] memory pools) internal view returns (V2PoolReserves[] memory) {
        V2PoolReserves[] memory reserves = new V2PoolReserves[](pools.length);
        for (uint256 i = 0; i < pools.length; i++) {
            (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast) = IUniswapV2Pool(pools[i]).getReserves();
            V2PoolReserves memory poolReserves = V2PoolReserves({
                pool: pools[i],
                reserve0: reserve0,
                reserve1: reserve1,
                blockTimestampLast: blockTimestampLast
            });
            reserves[i] = poolReserves;
        }
        return reserves;
    }

    function _getV3PoolState(V3Pool[] memory pools) internal view returns (V3PoolData[] memory) {
        V3PoolData[] memory allPoolData = new V3PoolData[](pools.length);

        for (uint256 i = 0; i < pools.length; i++) {
            allPoolData[i] = getV3PoolData(pools[i]);
        }

        return allPoolData;
    }

    function getV3PoolData(V3Pool memory _pool) internal view returns (V3PoolData memory) {
        IUniswapV3Pool pool = IUniswapV3Pool(_pool.addr);

        (uint160 sqrtPriceX96, int24 tick, , , , , ) = pool.slot0();

        int24 tickSpacing = calcTickSpacing(_pool.fee);
        (int16 wordPos, ) = position(tick / tickSpacing);
        (
            uint128 liquidityGross,
            int128 liquidityNet,
            uint256 feeGrowthOutside0X128,
            uint256 feeGrowthOutside1X128,
            ,
            ,
            ,
            bool initialized
        ) = pool.ticks(tick);

        return
            V3PoolData(
                _pool.addr,
                balanceOf(_pool.tokenA, _pool.addr),
                balanceOf(_pool.tokenB, _pool.addr),
                pool.feeGrowthGlobal0X128(),
                pool.feeGrowthGlobal1X128(),
                feeGrowthOutside0X128,
                feeGrowthOutside1X128,
                pool.liquidity(),
                sqrtPriceX96,
                tick,
                pool.tickBitmap(wordPos),
                wordPos,
                liquidityNet,
                liquidityGross,
                initialized
            );
    }

    function _getV4PoolState(V4Pool[] memory pools, address stateView) internal view returns (V4PoolData[] memory) {
        V4PoolData[] memory allPoolData = new V4PoolData[](pools.length);

        IStateView stateViewContract = IStateView(stateView);

        for (uint256 i = 0; i < pools.length; i++) {
            (uint160 sqrtPriceX96, int24 tick, , ) = stateViewContract.getSlot0(pools[i].pool);
            (int16 wordPos, ) = position(tick / pools[i].tickSpacing);

            uint256 tickBitmap = stateViewContract.getTickBitmap(pools[i].pool, wordPos);
            uint128 liquidity = stateViewContract.getLiquidity(pools[i].pool);

            (uint128 liquidityGross, int128 liquidityNet) = stateViewContract.getTickLiquidity(pools[i].pool, tick);

            (uint256 feeGrowthGlobal0, uint256 feeGrowthGlobal1) = stateViewContract.getFeeGrowthGlobals(pools[i].pool);

            (uint256 feeGrowthOutside0X128, uint256 feeGrowthOutside1X128) = stateViewContract.getTickFeeGrowthOutside(
                pools[i].pool,
                tick
            );

            allPoolData[i] = V4PoolData(
                pools[i].pool,
                feeGrowthGlobal0,
                feeGrowthGlobal1,
                feeGrowthOutside0X128,
                feeGrowthOutside1X128,
                liquidity,
                sqrtPriceX96,
                tick,
                tickBitmap,
                wordPos,
                liquidityNet,
                liquidityGross
            );
        }

        return allPoolData;
    }

    function calcTickSpacing(uint24 fee) internal view returns (int24 tickSpacing) {
        if (fee <= FEE_LOWEST) return 1;
        else if (fee == FEE_LOW) return 10;
        else if (fee == FEE_MEDIUM) return 60;
        else if (fee == FEE_HIGH) return 200;
        else fee / 50;
    }

    function position(int24 tick) internal pure returns (int16 wordPos, uint8 bitPos) {
        wordPos = int16(tick >> 8);
        bitPos = uint8(uint24(tick) & 0xFF);
    }

    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(
                // The arguments of `mul` are evaluated from right to left.
                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)
                )
            )
        }
    }
}

// *****************************************************************************
// *                                                                           *
// *                               Interfaces                                  *
// *                                                                           *
// *****************************************************************************

interface IERC20 {
    function totalSupply() external view returns (uint256);
}

interface IUniswapV2Pool {
    function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
}

interface IUniswapV3Pool {
    function token0() external view returns (address);
    function token1() external view returns (address);
    function fee() external view returns (uint24);
    function slot0()
        external
        view
        returns (
            uint160 sqrtPriceX96,
            int24 tick,
            uint16 observationIndex,
            uint16 observationCardinality,
            uint16 observationCardinalityNext,
            uint8 feeProtocol,
            bool unlocked
        );
    function liquidity() external view returns (uint128);
    function tickBitmap(int16 wordPos) external view returns (uint256);
    function feeGrowthGlobal0X128() external view returns (uint256);
    function feeGrowthGlobal1X128() external view returns (uint256);
    function ticks(
        int24 tick
    )
        external
        view
        returns (
            uint128 liquidityGross,
            int128 liquidityNet,
            uint256 feeGrowthOutside0X128,
            uint256 feeGrowthOutside1X128,
            int56 tickCumulativeOutside,
            uint160 secondsPerLiquidityOutsideX128,
            uint32 secondsOutside,
            bool initialized
        );
}

interface IV2Factory {
    function getPair(address tokenA, address tokenB) external view returns (address);
}

interface IV3Factory {
    function getPool(address tokenA, address tokenB, uint24 fee) external view returns (address);
}

interface IStateView {
    function getLiquidity(bytes32 poolId) external view returns (uint128 liquidity);
    function getSlot0(
        bytes32 poolId
    ) external view returns (uint160 sqrtPriceX96, int24 tick, uint24 protocolFee, uint24 lpFee);

    function getTickBitmap(bytes32 poolId, int16 tick) external view returns (uint256 tickBitmap);

    function getFeeGrowthGlobals(
        bytes32 poolId
    ) external view returns (uint256 feeGrowthGlobal0, uint256 feeGrowthGlobal1);

    function getTickFeeGrowthOutside(
        bytes32 poolId,
        int24 tick
    ) external view returns (uint256 feeGrowthOutside0X128, uint256 feeGrowthOutside1X128);

    function getTickLiquidity(
        bytes32 poolId,
        int24 tick
    ) external view returns (uint128 liquidityGross, int128 liquidityNet);
}
"
    },
    "src/lib/MetadataReader.sol": {
      "content": "// 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("decimals()")))`.
    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("decimals()"), gasStipend))`.
    function readDecimals(address target, uint256 gasStipend) internal view returns (uint8) {
        return uint8(_uint(target, _ptr(0x313ce567), gasStipend));
    }

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

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

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

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

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

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

    /// @dev Casts the `data` into a pointer.
    function _ptr(bytes memory data) private pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := data
        }
    }
}"
    }
  },
  "settings": {
    "remappings": [
      "forge-std/=lib/forge-std/src/"
    ],
    "optimizer": {
      "enabled": true,
      "runs": 200
    },
    "metadata": {
      "useLiteralContent": false,
      "bytecodeHash": "ipfs",
      "appendCBOR": true
    },
    "outputSelection": {
      "*": {
        "*": [
          "evm.bytecode",
          "evm.deployedBytecode",
          "devdoc",
          "userdoc",
          "metadata",
          "abi"
        ]
      }
    },
    "evmVersion": "prague",
    "viaIR": true
  }
}}

Tags:
DeFi, Liquidity, Factory|addr:0xbb7b2f9a196b898f14dc6c40a536231037973e39|verified:true|block:23710348|tx:0xab9c9ef8694e85a1e8090ffdef8ad39d820873c3a2aa7fbb404c2a039268dadb|first_check:1762082662

Submitted on: 2025-11-02 12:24:23

Comments

Log in to comment.

No comments yet.