eth_getStorageAt
Accesses raw storage data from a specific position within a smart contract on IoTeX One. This powerful method enables direct inspection of contract state variables, proxy implementations, and complex storage structures.
Parameters​
Parameter | Type | Required | Description |
---|---|---|---|
address | string | Yes | The contract address (20 bytes) to read storage from |
position | string | Yes | The storage slot position as hex (32 bytes, 0x-prefixed) |
blockNumber | string | Yes | Block number in hex or block tag ("latest", "earliest", "pending") |
Storage Layout Understanding​
- State variables: Sequential slots starting from 0x0
- Mapping values:
keccak256(abi.encodePacked(key, slot))
- Dynamic arrays: Array length at slot, data at
keccak256(slot) + index
- String/bytes: Length and data encoding based on size
Returns​
A 32-byte hex string representing the storage value. Smaller values are left-padded with zeros to reach the full 32-byte length.
Implementation Examples​
- cURL
- JavaScript
- Python
# Read storage from ARB token contract on IoTeX
curl -X POST https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "eth_getStorageAt",
"params": [
"0x912CE59144191C1204E64559FE8253a0e49E6548",
"0x3",
"latest"
],
"id": 1
}'
// Retrieve storage from IoTeX contracts
const getContractStorage = async (address, slot, block = 'latest') => {
const response = await fetch('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
method: 'eth_getStorageAt',
params: [address, slot, block],
id: 1
})
});
const data = await response.json();
return data.result;
};
// Example: Read from ARB token contract
const arbToken = '0x912CE59144191C1204E64559FE8253a0e49E6548';
const totalSupplySlot = '0x3'; // Slot 3 contains total supply
getContractStorage(arbToken, totalSupplySlot)
.then(result => {
console.log('Total Supply:', BigInt(result).toString());
});
// Helper: Calculate mapping storage position
const calculateMappingSlot = (key, baseSlot) => {
const keyPadded = key.replace('0x', '').padStart(64, '0');
const slotPadded = baseSlot.replace('0x', '').padStart(64, '0');
return ethers.utils.keccak256('0x' + keyPadded + slotPadded);
};
import requests
from web3 import Web3
class IoTeXStorageReader:
def __init__(self, api_key):
self.url = f'https://api-iotex-mainnet.n.dwellir.com/{api_key}'
self.w3 = Web3()
def get_storage_at(self, address, position, block='latest'):
"""Read storage from IoTeX contract"""
payload = {
"jsonrpc": "2.0",
"method": "eth_getStorageAt",
"params": [address, position, block],
"id": 1
}
response = requests.post(
self.url,
json=payload,
headers={'Content-Type': 'application/json'}
)
return response.json()['result']
def get_mapping_value(self, contract_addr, mapping_slot, key):
"""Get value from mapping storage"""
# Pad key to 32 bytes
key_padded = key.replace('0x', '').zfill(64)
slot_padded = hex(mapping_slot)[2:].zfill(64)
# Calculate storage position
position = self.w3.keccak(
bytes.fromhex(key_padded + slot_padded)
).hex()
return self.get_storage_at(contract_addr, position)
# Example usage
reader = IoTeXStorageReader('YOUR_API_KEY')
# Read from ARB token contract
arb_token = '0x912CE59144191C1204E64559FE8253a0e49E6548'
# Get total supply (slot 3)
total_supply = reader.get_storage_at(arb_token, '0x3')
print(f"Total Supply: {int(total_supply, 16)}")
# Get balance for specific address (balances mapping at slot 0)
user_address = '0x1234567890123456789012345678901234567890'
balance = reader.get_mapping_value(arb_token, 0, user_address)
print(f"User Balance: {int(balance, 16)}")
Response Example​
{
"jsonrpc": "2.0",
"id": 1,
"result": "0x00000000000000000000000000000000000000000000021e19e0c9bab2400000"
}
Common Use Cases​
- Token Analysis: Read balances, allowances, and total supply from ERC-20 contracts
- Proxy Contracts: Extract implementation addresses from upgradeable proxies
- Governance: Access voting power, proposal states, and delegation data
- DeFi Protocols: Inspect liquidity pools, reserves, and protocol parameters
- Security Audits: Verify contract state and detect anomalies
Storage Calculation Examples​
Simple Variables​
// First state variable is at slot 0
const slot0 = '0x0';
// Second state variable is at slot 1
const slot1 = '0x1';
Mappings​
// For mapping at slot 5, key = user address
const mappingSlot = 5;
const userKey = '0x742d35Cc6634C0532925a3b8D7aa86B2ecaedC9C';
const storagePosition = keccak256(userKey.padStart(64, '0') + mappingSlot.toString(16).padStart(64, '0'));
Dynamic Arrays​
// Array length at slot 8
const arrayLengthSlot = '0x8';
// First element at keccak256(8)
const firstElementSlot = keccak256('0x' + '8'.padStart(64, '0'));
Important Considerations​
- All storage values are exactly 32 bytes in length
- IoTeX maintains Ethereum storage compatibility
- Historical data available through archive node access
- Gas-optimized contracts may pack multiple values in single slots
- Storage slots are persistent across contract upgrades in proxy patterns
Need help? Contact our support team or check the IoTeX documentation.