eth_getStorageAt
Queries raw storage data from smart contracts deployed on Unichain. This method enables deep inspection of DeFi protocols, AMM pools, token balances, and other contract state variables essential for trading and liquidity analysis.
Parameters​
Parameter | Type | Required | Description |
---|---|---|---|
address | string | Yes | Contract address (20 bytes) to query storage from |
position | string | Yes | Storage slot position as hex string (32 bytes, 0x-prefixed) |
blockNumber | string | Yes | Block number in hex or block tag ("latest", "earliest", "pending") |
Unichain DeFi Storage Patterns​
- AMM pools: Reserve amounts, liquidity data, and fee calculations
- Token contracts: Balances, allowances, and total supply tracking
- Governance: Voting power, proposal states, and protocol parameters
- Yield farming: Staking rewards, pool shares, and harvest data
Returns​
A 32-byte hex string containing the storage value. Values are left-padded with zeros to maintain consistent 32-byte formatting.
Code Examples​
- cURL
- JavaScript
- Python
# Read storage from Uniswap V3 pool on Unichain
curl -X POST https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "eth_getStorageAt",
"params": [
"0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640",
"0x0",
"latest"
],
"id": 1
}'
// Unichain DeFi storage analyzer
class UnichainDeFiAnalyzer {
constructor(apiKey) {
this.endpoint = `https://api-unichain-mainnet.n.dwellir.com/${apiKey}`;
}
async getStorageAt(address, position, block = 'latest') {
const response = await fetch(this.endpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
method: 'eth_getStorageAt',
params: [address, position, block],
id: 1
})
});
const data = await response.json();
if (data.error) {
throw new Error(`RPC Error: ${data.error.message}`);
}
return data.result;
}
// Calculate mapping storage position
getMappingSlot(key, baseSlot) {
const keyPadded = key.replace('0x', '').padStart(64, '0');
const slotPadded = baseSlot.toString(16).padStart(64, '0');
return ethers.utils.keccak256('0x' + keyPadded + slotPadded);
}
// Parse DeFi-specific values
parseValue(hex, type, decimals = 18) {
const value = BigInt(hex);
switch(type) {
case 'token_amount':
return (Number(value) / Math.pow(10, decimals)).toFixed(decimals);
case 'liquidity':
return value.toString(); // Keep as string for precision
case 'price':
return Number(value) / Math.pow(10, 18); // Price typically in 18 decimals
case 'fee':
return Number(value) / 10000; // Fees in basis points
case 'bool':
return value > 0n;
case 'address':
return '0x' + hex.slice(-40);
default:
return hex;
}
}
// Get Uniswap V3 pool reserves
async getPoolReserves(poolAddress) {
// Slot 0 contains liquidity and sqrt price
const slot0 = await this.getStorageAt(poolAddress, '0x0');
// Extract sqrt price (first 160 bits) and liquidity
const sqrtPriceX96 = BigInt('0x' + slot0.slice(2, 42));
const liquidity = BigInt('0x' + slot0.slice(42));
return {
sqrtPriceX96: sqrtPriceX96.toString(),
liquidity: liquidity.toString(),
rawData: slot0
};
}
// Get ERC-20 token balance
async getTokenBalance(tokenAddress, userAddress) {
// Most ERC-20 tokens store balances at slot 0
const balanceSlot = this.getMappingSlot(userAddress, 0);
const balance = await this.getStorageAt(tokenAddress, balanceSlot);
return this.parseValue(balance, 'token_amount');
}
// Get token allowance
async getTokenAllowance(tokenAddress, owner, spender) {
// Allowances typically at slot 1 (nested mapping)
const ownerSlot = this.getMappingSlot(owner, 1);
const allowanceSlot = this.getMappingSlot(spender, BigInt(ownerSlot));
const allowance = await this.getStorageAt(tokenAddress, allowanceSlot);
return this.parseValue(allowance, 'token_amount');
}
// Get governance voting power
async getVotingPower(governanceContract, voter, proposalId = null) {
let votingSlot;
if (proposalId) {
// Proposal-specific voting power
votingSlot = this.getMappingSlot(
voter + proposalId.toString(16).padStart(64, '0'),
2
);
} else {
// General voting power
votingSlot = this.getMappingSlot(voter, 3);
}
const power = await this.getStorageAt(governanceContract, votingSlot);
return this.parseValue(power, 'token_amount');
}
}
// Example usage
const analyzer = new UnichainDeFiAnalyzer('YOUR_API_KEY');
// Analyze Uniswap V3 ETH/USDC pool
const ethUsdcPool = '0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640';
analyzer.getPoolReserves(ethUsdcPool)
.then(reserves => {
console.log('Pool Reserves:', reserves);
// Calculate price from sqrtPriceX96
const sqrtPrice = Number(reserves.sqrtPriceX96) / Math.pow(2, 96);
const price = Math.pow(sqrtPrice, 2);
console.log('ETH/USDC Price:', price);
});
// Check USDC balance for an address
const usdcAddress = '0xA0b86a33E6417abD4c07BC35f99c1B65d2b8fDf3';
const userAddress = '0x742d35Cc6634C0532925a3b8D7aa86B2ecaedC9C';
analyzer.getTokenBalance(usdcAddress, userAddress)
.then(balance => {
console.log('USDC Balance:', balance);
});
import requests
from web3 import Web3
from decimal import Decimal, getcontext
# Set precision for DeFi calculations
getcontext().prec = 50
class UnichainDeFiInspector:
def __init__(self, api_key):
self.api_url = f'https://api-unichain-mainnet.n.dwellir.com/{api_key}'
self.w3 = Web3()
def get_storage_at(self, address, position, block='latest'):
"""Read storage from Unichain contract"""
payload = {
"jsonrpc": "2.0",
"method": "eth_getStorageAt",
"params": [address, position, block],
"id": 1
}
response = requests.post(
self.api_url,
json=payload,
headers={'Content-Type': 'application/json'}
)
result = response.json()
if 'error' in result:
raise Exception(f"RPC Error: {result['error']['message']}")
return result['result']
def calculate_mapping_slot(self, key, base_slot):
"""Calculate storage position for mapping"""
if isinstance(key, str) and key.startswith('0x'):
key_bytes = bytes.fromhex(key[2:].zfill(64))
elif isinstance(key, int):
key_bytes = key.to_bytes(32, 'big')
else:
key_bytes = bytes.fromhex(str(key).zfill(64))
slot_bytes = base_slot.to_bytes(32, 'big')
position = self.w3.keccak(key_bytes + slot_bytes).hex()
return position
def parse_defi_value(self, hex_value, value_type, decimals=18):
"""Parse DeFi-specific values with high precision"""
raw_value = int(hex_value, 16)
if value_type == 'token_amount':
return Decimal(raw_value) / Decimal(10 ** decimals)
elif value_type == 'sqrt_price':
# For Uniswap V3 sqrt price calculation
return Decimal(raw_value) / Decimal(2 ** 96)
elif value_type == 'liquidity':
return Decimal(raw_value)
elif value_type == 'fee_rate':
return Decimal(raw_value) / Decimal(10000) # Basis points
elif value_type == 'price':
return Decimal(raw_value) / Decimal(10 ** 18)
elif value_type == 'address':
return '0x' + hex_value[-40:]
elif value_type == 'bool':
return raw_value > 0
else:
return hex_value
def get_uniswap_v3_pool_state(self, pool_address):
"""Get Uniswap V3 pool state from storage"""
# Slot 0: sqrtPriceX96, tick, observationIndex, observationCardinality, etc.
slot0_data = self.get_storage_at(pool_address, '0x0')
# Extract sqrt price (160 bits) and tick (24 bits)
slot0_int = int(slot0_data, 16)
sqrt_price_x96 = slot0_int & ((1 << 160) - 1)
tick = (slot0_int >> 160) & ((1 << 24) - 1)
# Handle signed tick
if tick >= (1 << 23):
tick -= (1 << 24)
return {
'sqrt_price_x96': sqrt_price_x96,
'tick': tick,
'price': self.calculate_price_from_sqrt(sqrt_price_x96),
'raw_slot0': slot0_data
}
def calculate_price_from_sqrt(self, sqrt_price_x96):
"""Calculate actual price from sqrtPriceX96"""
sqrt_price = Decimal(sqrt_price_x96) / Decimal(2 ** 96)
return sqrt_price ** 2
def get_token_balance(self, token_address, holder_address):
"""Get ERC-20 token balance"""
balance_slot = self.calculate_mapping_slot(holder_address, 0)
balance_hex = self.get_storage_at(token_address, balance_slot)
return self.parse_defi_value(balance_hex, 'token_amount')
def get_token_allowance(self, token_address, owner, spender):
"""Get ERC-20 token allowance"""
# First mapping: owner -> slot
owner_slot = self.calculate_mapping_slot(owner, 1)
# Second mapping: spender -> allowance
allowance_slot = self.calculate_mapping_slot(spender, int(owner_slot, 16))
allowance_hex = self.get_storage_at(token_address, allowance_slot)
return self.parse_defi_value(allowance_hex, 'token_amount')
def get_liquidity_position(self, position_manager, token_id):
"""Get Uniswap V3 position data"""
# Position data typically stored in mapping
position_slot = self.calculate_mapping_slot(token_id, 2)
position_hex = self.get_storage_at(position_manager, position_slot)
# Parse position data (this is simplified - actual position has multiple slots)
position_int = int(position_hex, 16)
return {
'raw_data': position_hex,
'position_id': token_id,
'has_position': position_int > 0
}
def analyze_defi_protocol(self, contract_address, protocol_type='uniswap_v3'):
"""Comprehensive DeFi protocol analysis"""
analysis = {
'contract': contract_address,
'protocol': protocol_type,
'storage_data': {}
}
if protocol_type == 'uniswap_v3':
# Get pool state
pool_state = self.get_uniswap_v3_pool_state(contract_address)
analysis['pool_state'] = pool_state
# Get fee tier (slot 2)
fee_hex = self.get_storage_at(contract_address, '0x2')
analysis['fee_tier'] = self.parse_defi_value(fee_hex, 'fee_rate')
elif protocol_type == 'erc20':
# Get total supply (usually slot 2)
total_supply_hex = self.get_storage_at(contract_address, '0x2')
analysis['total_supply'] = self.parse_defi_value(total_supply_hex, 'token_amount')
return analysis
# Example usage for Unichain DeFi analysis
inspector = UnichainDeFiInspector('YOUR_API_KEY')
# Analyze major DeFi contracts on Unichain
try:
# Example Uniswap V3 ETH/USDC pool analysis
eth_usdc_pool = '0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640'
pool_analysis = inspector.analyze_defi_protocol(eth_usdc_pool, 'uniswap_v3')
print(f"ETH/USDC Pool Analysis: {pool_analysis}")
# Check specific user balances
usdc_token = '0xA0b86a33E6417abD4c07BC35f99c1B65d2b8fDf3'
user_address = '0x742d35Cc6634C0532925a3b8D7aa86B2ecaedC9C'
usdc_balance = inspector.get_token_balance(usdc_token, user_address)
print(f"User USDC Balance: {usdc_balance}")
# Check allowances for trading
router_address = '0xE592427A0AEce92De3Edee1F18E0157C05861564'
allowance = inspector.get_token_allowance(usdc_token, user_address, router_address)
print(f"Router Allowance: {allowance}")
except Exception as e:
print(f"Error analyzing Unichain DeFi: {e}")
Response Example​
{
"jsonrpc": "2.0",
"id": 1,
"result": "0x000000000000000000000000000000000000000000000000000de0b6b3a7640000"
}
DeFi-Specific Applications​
- AMM Analysis: Monitor liquidity pools, reserve ratios, and trading fees
- Yield Farming: Track staking positions, reward accumulation, and pool shares
- Token Economics: Analyze supply distribution, holder balances, and transfer patterns
- Price Discovery: Extract price data from oracle contracts and AMM pools
- Governance Tracking: Monitor voting power, proposal states, and protocol parameters
Uniswap V3 Storage Layout​
Pool State (Slot 0)​
// Uniswap V3 pool slot 0 layout
const extractPoolState = (slot0Hex) => {
const slot0Int = BigInt(slot0Hex);
return {
sqrtPriceX96: slot0Int & ((1n << 160n) - 1n),
tick: Number((slot0Int >> 160n) & ((1n << 24n) - 1n)),
observationIndex: Number((slot0Int >> 184n) & ((1n << 16n) - 1n)),
observationCardinality: Number((slot0Int >> 200n) & ((1n << 16n) - 1n)),
observationCardinalityNext: Number((slot0Int >> 216n) & ((1n << 16n) - 1n)),
feeProtocol: Number((slot0Int >> 232n) & ((1n << 8n) - 1n)),
unlocked: Boolean((slot0Int >> 240n) & 1n)
};
};
ERC-20 Token Storage​
// Standard ERC-20 storage layout
const erc20Slots = {
balances: 0, // mapping(address => uint256)
allowances: 1, // mapping(address => mapping(address => uint256))
totalSupply: 2, // uint256
name: 3, // string
symbol: 4, // string
decimals: 5 // uint8
};
Liquidity Position Data​
// Uniswap V3 position manager storage
const positionSlots = {
positions: 2, // mapping(uint256 => Position)
ownerOf: 3, // mapping(uint256 => address)
getApproved: 4, // mapping(uint256 => address)
operators: 5 // mapping(address => mapping(address => bool))
};
Advanced DeFi Calculations​
- Price calculation:
price = (sqrtPriceX96 / 2^96)^2
- Liquidity calculation requires token reserves and current price
- Fee calculations depend on pool fee tier (0.01%, 0.05%, 0.3%, 1%)
- Position value requires current price and liquidity range
- Yield calculations need historical data and time-based analysis
Need help? Contact our support team or check the Unichain documentation.