# eth_getStorageAt - IoTeX RPC Method

Returns the value from a storage position at a given address on IoTeX. This provides direct access to the raw EVM storage of any smart contract, bypassing ABI encoding and public getter functions.

> **Why IoTeX?** Build on the leading DePIN infrastructure blockchain powering 130+ applications in the $27B+ DePIN ecosystem with W3bstream offchain compute, Quicksilver AI data verification, Vodafone partnership for 5M+ cell tower integration, and ioID device identity.

## When to Use This Method

`eth_getStorageAt` is essential for DePIN builders, IoT device manufacturers, and real-world AI application developers:

- **Reading Private State** - Access contract state variables that have no public getter, including variables marked as `private` or `internal` in Solidity
- **Proxy Implementation Verification** - Read the implementation address from EIP-1967 proxy storage slots to verify which logic contract a proxy delegates to on decentralized physical infrastructure (DePIN), IoT device identity (ioID), and AI-verified real-world data
- **Storage Layout Analysis** - Inspect raw storage slots for security auditing, debugging, or reverse-engineering contract behavior
- **State Change Monitoring** - Track specific storage slot changes across blocks to monitor protocol parameters, admin roles, or balances

## Request Parameters

- `address` (`DATA (20 bytes), required`): The address of the contract to read storage from
- `position` (`QUANTITY, required`): Hex-encoded storage slot position (e.g., 0x0 for the first slot)
- `blockParameter` (`QUANTITY|TAG, required`): Block number as hex, or tag: latest, earliest, pending

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getStorageAt",
  "params": [
    "0xA00744882684C3e4747fAEFd68D283eA44099D03",
    "0x0",
    "latest"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`DATA (32 bytes), required`): The 32-byte value stored at the requested position, zero-padded on the left

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x0000000000000000000000000000000000000000000000000000000000000001"
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: invalid address"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
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": [
      "0xA00744882684C3e4747fAEFd68D283eA44099D03",
      "0x0",
      "latest"
    ],
    "id": 1
  }'
```

```javascript
// Using fetch
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: ['0xA00744882684C3e4747fAEFd68D283eA44099D03', '0x0', 'latest'],
    id: 1
  })
});

const { result } = await response.json();
console.log('Storage slot 0:', result);

// Using ethers.js
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');
const address = '0xA00744882684C3e4747fAEFd68D283eA44099D03';

const slot0 = await provider.getStorage(address, 0);
console.log('Storage at slot 0:', slot0);

// Read a specific slot
const slot5 = await provider.getStorage(address, 5);
console.log('Storage at slot 5:', slot5);
```

```python
import requests

def get_storage_at(address, position, block='latest'):
    response = requests.post(
        'https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_getStorageAt',
            'params': [address, hex(position), block],
            'id': 1
        }
    )
    return response.json()['result']

address = '0xA00744882684C3e4747fAEFd68D283eA44099D03'
value = get_storage_at(address, 0)
print(f'Storage at slot 0: {value}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY'))
storage = w3.eth.get_storage_at(address, 0)
print(f'Storage at slot 0: {storage.hex()}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    address := common.HexToAddress("0xA00744882684C3e4747fAEFd68D283eA44099D03")
    slot := common.BigToHash(big.NewInt(0))

    value, err := client.StorageAt(context.Background(), address, slot, nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Storage at slot 0: 0x%x\n", value)
}
```

## Common Use Cases

### 1. Verify Proxy Implementation Address

Read the EIP-1967 implementation slot to verify which contract a proxy points to on IoTeX:

```javascript
import { JsonRpcProvider, keccak256, toUtf8Bytes } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

async function getProxyImplementation(proxyAddress) {
  // EIP-1967 implementation slot:
  // bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)
  const EIP1967_IMPL_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';

  const value = await provider.getStorage(proxyAddress, EIP1967_IMPL_SLOT);

  // Extract the address from the 32-byte value (last 20 bytes)
  const implAddress = '0x' + value.slice(26);

  if (implAddress === '0x' + '0'.repeat(40)) {
    console.log('Not a standard EIP-1967 proxy or no implementation set');
    return null;
  }

  console.log(`Proxy: ${proxyAddress}`);
  console.log(`Implementation: ${implAddress}`);
  return implAddress;
}

// Also check the admin slot
async function getProxyAdmin(proxyAddress) {
  const EIP1967_ADMIN_SLOT = '0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103';
  const value = await provider.getStorage(proxyAddress, EIP1967_ADMIN_SLOT);
  return '0x' + value.slice(26);
}
```

### 2. Read Solidity Mapping Values

Calculate the storage slot for a mapping entry and read it:

```javascript
import { JsonRpcProvider, keccak256, AbiCoder, zeroPadValue, toBeHex } from 'ethers';

const provider = new JsonRpcProvider('https://api-iotex-mainnet.n.dwellir.com/YOUR_API_KEY');

async function readMapping(contractAddress, mappingSlot, key) {
  // For mapping(address => uint256) at slot N:
  // slot = keccak256(abi.encode(key, N))
  const abiCoder = AbiCoder.defaultAbiCoder();
  const encoded = abiCoder.encode(
    ['address', 'uint256'],
    [key, mappingSlot]
  );
  const slot = keccak256(encoded);

  const value = await provider.getStorage(contractAddress, slot);
  return BigInt(value);
}

// Example: read an ERC-20 balance (balanceOf mapping is typically at slot 0 or 1)
const contractAddress = '0xA00744882684C3e4747fAEFd68D283eA44099D03';
const holderAddress = '0x1234567890abcdef1234567890abcdef12345678';
const balance = await readMapping(contractAddress, 0, holderAddress);
console.log('Token balance:', balance.toString());
```

### 3. Storage Layout Inspector

Scan multiple storage slots to analyze a contract's state:

```javascript
async function inspectStorage(provider, address, slotCount = 10) {
  console.log(`Inspecting storage for ${address} on IoTeX:`);
  console.log('─'.repeat(80));

  const results = [];
  for (let i = 0; i < slotCount; i++) {
    const value = await provider.getStorage(address, i);
    const isZero = value === '0x' + '0'.repeat(64);

    if (!isZero) {
      // Try to interpret the value
      const asNumber = BigInt(value);
      const asAddress = '0x' + value.slice(26);
      const hasAddressPattern = value.slice(2, 26) === '0'.repeat(24);

      console.log(`Slot ${i}: ${value}`);
      if (hasAddressPattern && asAddress !== '0x' + '0'.repeat(40)) {
        console.log(`  → Possible address: ${asAddress}`);
      } else {
        console.log(`  → As uint256: ${asNumber}`);
      }

      results.push({ slot: i, value, asNumber });
    }
  }

  return results;
}
```

## Best Practices

- Use known storage slot constants (EIP-1967, EIP-1822, OpenZeppelin layout) instead of guessing slot positions
- For mappings, calculate the storage slot using `keccak256(abi.encode(key, baseSlot))` per Solidity storage layout rules
- Read multiple slots in parallel when inspecting contract state to reduce total API calls
- Monitor proxy storage slots (implementation, admin, beacon) to detect unexpected upgrades
- For packed structs, understand that multiple variables may share a single 32-byte slot

## Related Methods

- [`eth_call`](https://www.dwellir.com/docs/iotex/eth_call) - Execute a contract function call without a transaction
- [`eth_getCode`](https://www.dwellir.com/docs/iotex/eth_getCode) - Get the bytecode deployed at an address
- [`eth_getBalance`](https://www.dwellir.com/docs/iotex/eth_getBalance) - Get the ETH balance of an address
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/iotex/eth_getBlockByNumber) - Get block details for historical storage queries
