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
}
}}
Submitted on: 2025-11-02 12:24:23
Comments
Log in to comment.
No comments yet.